1
0
mirror of https://github.com/Sonarr/Sonarr.git synced 2026-04-17 21:26:13 -04:00

Compare commits

..

44 Commits

Author SHA1 Message Date
Mark McDowall
d336aaf3f0 Fixed: Don't clone indexer API Key
Closes #6265
2024-01-19 21:30:34 -08:00
bakerboy448
ec40bc6eea Improve Release Title Custom Format debugging
Towards #5598
2024-01-19 21:30:24 -08:00
Mark McDowall
75bb34afaa Bump version to 4.0.1 2024-01-19 19:26:38 -08:00
Stevie Robinson
de1cc25c90 Translate backend: Autotagging + CF specs, Metadata + ImportLists
Signed-off-by: Stevie Robinson <stevie.robinson@gmail.com>
2024-01-18 21:47:03 -08:00
Mark McDowall
9884f6f282 Fixed: Icons on full color calendar events
Closes #6331
2024-01-19 00:43:51 -05:00
Qstick
e792db4d33 New: Improve All Series call by using dictionary for stats iteration 2024-01-18 21:43:34 -08:00
Bogdan
2dbf5b5a71 Check Content-Type in FileList parser 2024-01-18 21:43:17 -08:00
Stevie Robinson
c6bb6ad878 Round off the seeded ratio when checking for removal candidates
Signed-off-by: Stevie Robinson <stevie.robinson@gmail.com>
2024-01-18 21:43:07 -08:00
Bogdan
bfd24da2d9 Fixed: Importing Plex RSS lists with invalid items (#6374) 2024-01-19 00:42:51 -05:00
Stevie Robinson
8dd3b45c90 New: Drop commands table content before postgres migration
Signed-off-by: Stevie Robinson <stevie.robinson@gmail.com>
2024-01-19 00:42:31 -05:00
Stevie Robinson
0b0f21d0ac Update install.sh to not prompt for package installation
Script will exit without input if a prereq package is missing
2024-01-18 21:41:38 -08:00
Sonarr
738f5c58ad Automated API Docs update
ignore-downstream
2024-01-18 21:41:30 -08:00
Weblate
9a7b5bf14e Multiple Translations updated by Weblate
ignore-downstream

Co-authored-by: Blair Noctis <fqmxz5hyfba7ft85@neon.casa>
Co-authored-by: Dani Talens <databio@gmail.com>
Co-authored-by: Havok Dan <havokdan@yahoo.com.br>
Co-authored-by: Oskari Lavinto <olavinto@protonmail.com>
Co-authored-by: Petr Vojar <vojar.petr@outlook.com>
Co-authored-by: Weblate <noreply@weblate.org>
Co-authored-by: crayon3shawn <crayon3shawn@gmail.com>
Translate-URL: https://translate.servarr.com/projects/servarr/sonarr/
Translate-URL: https://translate.servarr.com/projects/servarr/sonarr/ca/
Translate-URL: https://translate.servarr.com/projects/servarr/sonarr/cs/
Translate-URL: https://translate.servarr.com/projects/servarr/sonarr/fi/
Translate-URL: https://translate.servarr.com/projects/servarr/sonarr/pt_BR/
Translate-URL: https://translate.servarr.com/projects/servarr/sonarr/zh_CN/
Translate-URL: https://translate.servarr.com/projects/servarr/sonarr/zh_TW/
Translation: Servarr/Sonarr
2024-01-18 21:41:14 -08:00
Mark McDowall
e1260d504e Re-enable deploy 2024-01-15 21:55:35 -08:00
Sonarr
736651324f Automated API Docs update
ignore-downstream
2024-01-15 21:55:22 -08:00
Bogdan
489f03441b Fixed: Filter history by multiple event types 2024-01-16 00:54:27 -05:00
Stevie Robinson
e4b5d559df Sort Custom Filters
Closes #6334
2024-01-16 00:53:21 -05:00
Stevie Robinson
07fbb0d1f4 Add missing translation keys from Indexer Settings
Signed-off-by: Stevie Robinson <stevie.robinson@gmail.com>
2024-01-16 00:52:55 -05:00
Stevie Robinson
666455f9b1 New: Add 'zhtw' and 'yue' language codes as Chinese language
Closes #6363
2024-01-16 00:52:40 -05:00
Bogdan
091449d9bf Throw download as failed for invalid magnet links 2024-01-15 21:51:17 -08:00
Qstick
f87a66fcba Improved http timeout handling 2024-01-15 21:51:02 -08:00
Blair Noctis
1bba7e177b Fixed: Improve help text for download client priority
Closes #6270
2024-01-16 00:50:25 -05:00
Rubicj
57445bbe57 New: Added column in Queue
Closes #6270
2024-01-16 00:28:28 -05:00
Qstick
ec91142c85 Fixed: Only use frames for Primary video stream for analysis
(cherry picked from commit 581828b0dcfcd4aa1ae581b899f812071457c9ca)
2024-01-15 23:03:46 -06:00
Mark McDowall
0685896ed8 Fixed: Prevent selecting season or episode in Manual Import if series or episode is not selected
Closes #6354
2024-01-14 12:37:33 -08:00
Mark McDowall
ee0048c768 Fixed: Reprocessing multi-language file in Manual Import 2024-01-14 12:37:33 -08:00
bakerboy448
16e5ffa467 Update logging to indicate a hardlink is being attempted 2024-01-14 15:16:53 -05:00
Mark McDowall
431c66c7c1 Update PR Template
[skip ci]
2024-01-14 12:12:30 -08:00
Mark McDowall
57bd6539c8 Update bug_report.yml
[skip ci]
2024-01-14 12:44:37 -05:00
Mark McDowall
637cb1711d Update PR template
[skip ci]
2024-01-14 12:43:14 -05:00
Weblate
7e011df2b2 Multiple Translations updated by Weblate
ignore-downstream

Co-authored-by: Daniele Prevedello <dprevedello86@gmail.com>
Co-authored-by: DimitriDR <dimitridroeck@gmail.com>
Co-authored-by: Fixer <ygj59783@zslsz.com>
Co-authored-by: Havok Dan <havokdan@yahoo.com.br>
Co-authored-by: Oskari Lavinto <olavinto@protonmail.com>
Co-authored-by: Watashi <drazy24@gmail.com>
Co-authored-by: Weblate <noreply@weblate.org>
Co-authored-by: hansaudun <hans@n5.no>
Co-authored-by: hcharbonnier <hugues.charbonnier@gmail.com>
Translate-URL: https://translate.servarr.com/projects/servarr/sonarr/fi/
Translate-URL: https://translate.servarr.com/projects/servarr/sonarr/fr/
Translate-URL: https://translate.servarr.com/projects/servarr/sonarr/it/
Translate-URL: https://translate.servarr.com/projects/servarr/sonarr/nb_NO/
Translate-URL: https://translate.servarr.com/projects/servarr/sonarr/pt_BR/
Translate-URL: https://translate.servarr.com/projects/servarr/sonarr/zh_CN/
Translation: Servarr/Sonarr
2024-01-13 17:07:06 -08:00
Stevie Robinson
79907c881c Add: New icon for deleted episodes with status missing from disk
Signed-off-by: Stevie Robinson <stevie.robinson@gmail.com>
2024-01-13 16:35:13 -08:00
Mark McDowall
db6a627983 Don't write global.json while updating API docs 2024-01-13 16:33:17 -08:00
Weblate
d76a489be6 Multiple Translations updated by Weblate
ignore-downstream

Co-authored-by: Fixer <ygj59783@zslsz.com>
Co-authored-by: Oskari Lavinto <olavinto@protonmail.com>
Co-authored-by: Watashi <drazy24@gmail.com>
Translate-URL: https://translate.servarr.com/projects/servarr/sonarr/fi/
Translate-URL: https://translate.servarr.com/projects/servarr/sonarr/fr/
Translate-URL: https://translate.servarr.com/projects/servarr/sonarr/zh_CN/
Translation: Servarr/Sonarr
2024-01-13 16:33:01 -08:00
Mark McDowall
fd17df0dd0 New: Optional directory setting for Aria2
Closes #6343
2024-01-13 16:32:09 -08:00
Mark McDowall
53cf530893 Fixed: Series posters flickering when width changes repeatedly
Closes #6311
2024-01-13 16:31:58 -08:00
Mark McDowall
91f33c670e Fix post-build test reporting and report summary 2024-01-13 11:32:01 -08:00
Mark McDowall
d322619733 Temporarily disable deploy 2024-01-12 17:45:32 -08:00
Mark McDowall
1182798929 Actually run Windows integration tests 2024-01-12 17:45:32 -08:00
Mark McDowall
ad0249c7db Use publish-unit-test-result-action for test result reporting 2024-01-12 17:45:32 -08:00
Mark McDowall
3259e6dc10 Download artifacts for Publish Test Results workflow 2024-01-12 17:45:32 -08:00
Mark McDowall
541d3307e1 Don't use TestCase for single test 2024-01-12 17:45:32 -08:00
Mark McDowall
ad60352bae Ignore CA1825 2024-01-12 17:45:32 -08:00
Mark McDowall
02e051580c Separate publishing of test results for PRs from forks 2024-01-12 11:56:45 -05:00
135 changed files with 1439 additions and 454 deletions

View File

@@ -203,6 +203,7 @@ dotnet_diagnostic.CA1819.severity = suggestion
dotnet_diagnostic.CA1822.severity = suggestion
dotnet_diagnostic.CA1823.severity = suggestion
dotnet_diagnostic.CA1824.severity = suggestion
dotnet_diagnostic.CA1825.severity = suggestion
dotnet_diagnostic.CA2000.severity = suggestion
dotnet_diagnostic.CA2002.severity = suggestion
dotnet_diagnostic.CA2007.severity = suggestion

View File

@@ -1,5 +1,5 @@
name: Bug Report
description: 'Support Requests will be closed immediately, if you are not 100% certain this is a bug please go to our Reddit, Discord, Forums, or IRC first. Only bug reports for v4 will be accepted, older versions are EOL & unsupported.'
description: 'Only bug reports for v4 will be accepted, older versions are no longer receiving bug fixes and support issues will be closed immediately.'
labels: ['needs-triage']
body:
- type: checkboxes

View File

@@ -1,14 +1,15 @@
#### Database Migration
YES | NO
#### Description
A few sentences describing the overall goals of the pull request's commits.
#### Todos
- [ ] Tests
- [ ] Wiki Updates
<!-- Remove any of the following sections if they are not used -->
#### Screenshots for UI Changes
#### Database Migration
YES - ###
#### Issues Fixed or Closed by this PR
* Closes #
*

View File

@@ -77,12 +77,20 @@ runs:
- name: Run tests
shell: bash
run: dotnet test ./_tests/Sonarr.*.Test.dll --filter "${{ inputs.filter }}" --logger trx --results-directory "${{ env.RESULTS_NAME }}"
run: dotnet test ./_tests/Sonarr.*.Test.dll --filter "${{ inputs.filter }}" --logger "trx;LogFileName=${{ env.RESULTS_NAME }}.trx"
- name: Upload Test Results
if: ${{ !cancelled() }}
uses: actions/upload-artifact@v4
with:
name: results-${{ env.RESULTS_NAME }}
path: TestResults/*.trx
- name: Publish Test Results
if: ${{ !cancelled() }}
uses: phoenix-actions/test-reporting@v12
with:
name: ${{ env.RESULTS_NAME }}
path: ${{ env.RESULTS_NAME }}/*.trx
name: Test Results
output-to: step-summary
path: '*.trx'
reporter: dotnet-trx
working-directory: TestResults

View File

@@ -31,12 +31,6 @@ jobs:
- name: Setup dotnet
uses: actions/setup-dotnet@v3
id: setup-dotnet
with:
dotnet-version: '6.0.x'
- name: Create temporary global.json
run: |
echo '{"sdk":{"version": "${{ steps.setup-dotnet.outputs.dotnet-version }}" } }' > ./global.json
- name: Create openapi.json
run: ./docs.sh Linux

View File

@@ -17,7 +17,7 @@ env:
FRAMEWORK: net6.0
BRANCH: ${{ github.head_ref || github.ref_name }}
SONARR_MAJOR_VERSION: 4
VERSION: 4.0.0
VERSION: 4.0.1
jobs:
backend:
@@ -188,7 +188,7 @@ jobs:
binary_path: osx-x64/${{ needs.backend.outputs.framework }}/Sonarr
- os: windows-latest
artifact: tests-win-x64
filter: TestCategory!=ManualTest&TestCategory=WINDOWS&TestCategory=IntegrationTest
filter: TestCategory!=ManualTest&TestCategory!=LINUX&TestCategory=IntegrationTest
binary_artifact: build_windows
binary_path: win-x64/${{ needs.backend.outputs.framework }}/Sonarr
runs-on: ${{ matrix.os }}

View File

@@ -0,0 +1,41 @@
name: Publish Test Results
on:
workflow_run:
workflows: ['Build']
types:
- completed
permissions:
contents: read
actions: read
checks: write
jobs:
report:
if: ${{ github.event.workflow_run.conclusion != 'skipped' && github.event.workflow_run.conclusion != 'cancelled' }}
runs-on: ubuntu-latest
steps:
- name: Check out
uses: actions/checkout@v3
- name: Download Test Reports
uses: actions/download-artifact@v4
with:
path: test-results
pattern: results-*
merge-multiple: true
repository: ${{ github.event.repository.owner.login }}/${{ github.event.repository.name }}
run-id: ${{ github.event.workflow_run.id }}
github-token: ${{ secrets.GITHUB_TOKEN }}
- name: Publish Test Results
uses: phoenix-actions/test-reporting@v12
with:
list-suites: failed
list-tests: failed
name: Test Results
only-summary: true
path: '*.trx'
reporter: dotnet-trx
working-directory: test-results

View File

@@ -98,7 +98,7 @@ echo "Directories created"
echo ""
echo "Installing pre-requisite Packages"
# shellcheck disable=SC2086
apt update && apt install $app_prereq
apt update && apt install -y $app_prereq
echo ""
ARCH=$(dpkg --print-architecture)
# get arch

View File

@@ -6,7 +6,7 @@ import { icons, kinds } from 'Helpers/Props';
import translate from 'Utilities/String/translate';
import styles from './HistoryEventTypeCell.css';
function getIconName(eventType) {
function getIconName(eventType, data) {
switch (eventType) {
case 'grabbed':
return icons.DOWNLOADING;
@@ -17,7 +17,7 @@ function getIconName(eventType) {
case 'downloadFailed':
return icons.DOWNLOADING;
case 'episodeFileDeleted':
return icons.DELETE;
return data.reason === 'MissingFromDisk' ? icons.FILE_MISSING : icons.DELETE;
case 'episodeFileRenamed':
return icons.ORGANIZE;
case 'downloadIgnored':
@@ -47,7 +47,7 @@ function getTooltip(eventType, data) {
case 'downloadFailed':
return translate('DownloadFailedEpisodeTooltip');
case 'episodeFileDeleted':
return translate('EpisodeFileDeletedTooltip');
return data.reason === 'MissingFromDisk' ? translate('EpisodeFileMissingTooltip') : translate('EpisodeFileDeletedTooltip');
case 'episodeFileRenamed':
return translate('EpisodeFileRenamedTooltip');
case 'downloadIgnored':
@@ -58,7 +58,7 @@ function getTooltip(eventType, data) {
}
function HistoryEventTypeCell({ eventType, data }) {
const iconName = getIconName(eventType);
const iconName = getIconName(eventType, data);
const iconKind = getIconKind(eventType);
const tooltip = getTooltip(eventType, data);

View File

@@ -100,6 +100,7 @@ class QueueRow extends Component {
outputPath,
downloadClient,
estimatedCompletionTime,
added,
timeleft,
size,
sizeleft,
@@ -362,6 +363,15 @@ class QueueRow extends Component {
);
}
if (name === 'added') {
return (
<RelativeDateCellConnector
key={name}
date={added}
/>
);
}
if (name === 'actions') {
return (
<TableRowCell
@@ -441,6 +451,7 @@ QueueRow.propTypes = {
outputPath: PropTypes.string,
downloadClient: PropTypes.string,
estimatedCompletionTime: PropTypes.string,
added: PropTypes.string,
timeleft: PropTypes.string,
size: PropTypes.number,
sizeleft: PropTypes.number,

View File

@@ -44,7 +44,16 @@ export interface CustomFilter {
filers: PropertyFilter[];
}
export interface AppSectionState {
dimensions: {
isSmallScreen: boolean;
width: number;
height: number;
};
}
interface AppState {
app: AppSectionState;
calendar: CalendarAppState;
commands: CommandAppState;
episodeFiles: EpisodeFilesAppState;

View File

@@ -52,6 +52,10 @@ $fullColorGradient: rgba(244, 245, 246, 0.2);
.statusContainer {
display: flex;
align-items: center;
&:global(.fullColor) {
filter: var(--calendarFullColorFilter)
}
}
.statusIcon {

View File

@@ -102,7 +102,12 @@ class CalendarEvent extends Component {
{series.title}
</div>
<div className={styles.statusContainer}>
<div
className={classNames(
styles.statusContainer,
fullColorEvents && 'fullColor'
)}
>
{
missingAbsoluteNumber ?
<Icon
@@ -128,6 +133,7 @@ class CalendarEvent extends Component {
<span className={styles.statusIcon}>
<CalendarEventQueueDetails
{...queueItem}
fullColorEvents={fullColorEvents}
/>
</span> :
null
@@ -150,7 +156,7 @@ class CalendarEvent extends Component {
<Icon
className={styles.statusIcon}
name={icons.EPISODE_FILE}
kind={fullColorEvents ? kinds.DEFAULT : kinds.WARNING}
kind={kinds.WARNING}
title={translate('QualityCutoffNotMet')}
/> :
null
@@ -160,9 +166,8 @@ class CalendarEvent extends Component {
episodeNumber === 1 && seasonNumber > 0 ?
<Icon
className={styles.statusIcon}
name={icons.INFO}
name={icons.PREMIERE}
kind={kinds.INFO}
darken={fullColorEvents}
title={seasonNumber === 1 ? translate('SeriesPremiere') : translate('SeasonPremiere')}
/> :
null
@@ -173,8 +178,8 @@ class CalendarEvent extends Component {
finaleType ?
<Icon
className={styles.statusIcon}
name={icons.INFO}
kind={fullColorEvents ? kinds.DEFAULT : kinds.WARNING}
name={finaleType === 'series' ? icons.FINALE_SERIES : icons.FINALE_SEASON}
kind={finaleType === 'series' ? kinds.DANGER : kinds.WARNING}
title={getFinaleTypeName(finaleType)}
/> :
null
@@ -187,7 +192,6 @@ class CalendarEvent extends Component {
className={styles.statusIcon}
name={icons.INFO}
kind={kinds.PINK}
darken={fullColorEvents}
title={translate('Special')}
/> :
null

View File

@@ -50,6 +50,15 @@
margin-bottom: 5px;
}
.statusContainer {
display: flex;
align-items: center;
&:global(.fullColor) {
filter: var(--calendarFullColorFilter)
}
}
.statusIcon {
margin-left: 3px;
}

View File

@@ -16,6 +16,7 @@ interface CssExports {
'onAir': string;
'premiere': string;
'seriesTitle': string;
'statusContainer': string;
'statusIcon': string;
'unaired': string;
'unmonitored': string;

View File

@@ -145,45 +145,51 @@ class CalendarEventGroup extends Component {
{series.title}
</div>
{
isMissingAbsoluteNumber &&
<Icon
containerClassName={styles.statusIcon}
name={icons.WARNING}
title={translate('EpisodeMissingAbsoluteNumber')}
/>
}
<div
className={classNames(
styles.statusContainer,
fullColorEvents && 'fullColor'
)}
>
{
isMissingAbsoluteNumber &&
<Icon
containerClassName={styles.statusIcon}
name={icons.WARNING}
title={translate('EpisodeMissingAbsoluteNumber')}
/>
}
{
anyDownloading &&
<Icon
containerClassName={styles.statusIcon}
name={icons.DOWNLOADING}
title={translate('AnEpisodeIsDownloading')}
/>
}
{
anyDownloading &&
<Icon
containerClassName={styles.statusIcon}
name={icons.DOWNLOADING}
title={translate('AnEpisodeIsDownloading')}
/>
}
{
firstEpisode.episodeNumber === 1 && seasonNumber > 0 &&
<Icon
containerClassName={styles.statusIcon}
name={icons.INFO}
kind={kinds.INFO}
darken={fullColorEvents}
title={seasonNumber === 1 ? translate('SeriesPremiere') : translate('SeasonPremiere')}
/>
}
{
firstEpisode.episodeNumber === 1 && seasonNumber > 0 &&
<Icon
containerClassName={styles.statusIcon}
name={icons.PREMIERE}
kind={kinds.INFO}
title={seasonNumber === 1 ? translate('SeriesPremiere') : translate('SeasonPremiere')}
/>
}
{
showFinaleIcon &&
lastEpisode.finaleType ?
<Icon
containerClassName={styles.statusIcon}
name={icons.INFO}
kind={fullColorEvents ? kinds.DEFAULT : kinds.WARNING}
title={getFinaleTypeName(lastEpisode.finaleType)}
/> : null
}
{
showFinaleIcon &&
lastEpisode.finaleType ?
<Icon
containerClassName={styles.statusIcon}
name={lastEpisode.finaleType === 'series' ? icons.FINALE_SERIES : icons.FINALE_SEASON}
kind={lastEpisode.finaleType === 'series' ? kinds.DANGER : kinds.WARNING}
title={getFinaleTypeName(lastEpisode.finaleType)}
/> : null
}
</div>
</div>
<div className={styles.airingInfo}>

View File

@@ -22,9 +22,20 @@ function Legend(props) {
if (showFinaleIcon) {
iconsToShow.push(
<LegendIconItem
name="Finale"
icon={icons.INFO}
kind={fullColorEvents ? kinds.DEFAULT : kinds.WARNING}
name={translate('SeasonFinale')}
icon={icons.FINALE_SEASON}
kind={kinds.WARNING}
fullColorEvents={fullColorEvents}
tooltip={translate('CalendarLegendSeriesFinaleTooltip')}
/>
);
iconsToShow.push(
<LegendIconItem
name={translate('SeriesFinale')}
icon={icons.FINALE_SERIES}
kind={kinds.DANGER}
fullColorEvents={fullColorEvents}
tooltip={translate('CalendarLegendSeriesFinaleTooltip')}
/>
);
@@ -33,10 +44,10 @@ function Legend(props) {
if (showSpecialIcon) {
iconsToShow.push(
<LegendIconItem
name="Special"
name={translate('Special')}
icon={icons.INFO}
kind={kinds.PINK}
darken={fullColorEvents}
fullColorEvents={fullColorEvents}
tooltip={translate('SpecialEpisode')}
/>
);
@@ -45,9 +56,10 @@ function Legend(props) {
if (showCutoffUnmetIcon) {
iconsToShow.push(
<LegendIconItem
name="Cutoff Not Met"
name={translate('Cutoff Not Met')}
icon={icons.EPISODE_FILE}
kind={fullColorEvents ? kinds.DEFAULT : kinds.WARNING}
kind={kinds.WARNING}
fullColorEvents={fullColorEvents}
tooltip={translate('QualityCutoffNotMet')}
/>
);
@@ -112,10 +124,10 @@ function Legend(props) {
<div>
<LegendIconItem
name="Premiere"
icon={icons.INFO}
name={translate('Premiere')}
icon={icons.PREMIERE}
kind={kinds.INFO}
darken={true}
fullColorEvents={fullColorEvents}
tooltip={translate('CalendarLegendSeriesPremiereTooltip')}
/>
@@ -129,6 +141,12 @@ function Legend(props) {
{iconsToShow[2]}
</div>
}
{
iconsToShow.length > 3 &&
<div>
{iconsToShow[3]}
</div>
}
</div>
);
}

View File

@@ -7,4 +7,8 @@
.icon {
margin-right: 5px;
&:global(.fullColorEvents) {
filter: var(--calendarFullColorFilter)
}
}

View File

@@ -1,3 +1,4 @@
import classNames from 'classnames';
import PropTypes from 'prop-types';
import React from 'react';
import Icon from 'Components/Icon';
@@ -6,9 +7,9 @@ import styles from './LegendIconItem.css';
function LegendIconItem(props) {
const {
name,
fullColorEvents,
icon,
kind,
darken,
tooltip
} = props;
@@ -18,9 +19,11 @@ function LegendIconItem(props) {
title={tooltip}
>
<Icon
className={styles.icon}
className={classNames(
styles.icon,
fullColorEvents && 'fullColorEvents'
)}
name={icon}
darken={darken}
kind={kind}
/>
@@ -31,14 +34,10 @@ function LegendIconItem(props) {
LegendIconItem.propTypes = {
name: PropTypes.string.isRequired,
fullColorEvents: PropTypes.bool.isRequired,
icon: PropTypes.object.isRequired,
kind: PropTypes.string.isRequired,
darken: PropTypes.bool.isRequired,
tooltip: PropTypes.string.isRequired
};
LegendIconItem.defaultProps = {
darken: false
};
export default LegendIconItem;

View File

@@ -30,22 +30,24 @@ function CustomFiltersModalContent(props) {
<ModalBody>
{
customFilters.map((customFilter) => {
return (
<CustomFilter
key={customFilter.id}
id={customFilter.id}
label={customFilter.label}
filters={customFilter.filters}
selectedFilterKey={selectedFilterKey}
isDeleting={isDeleting}
deleteError={deleteError}
dispatchSetFilter={dispatchSetFilter}
dispatchDeleteCustomFilter={dispatchDeleteCustomFilter}
onEditPress={onEditCustomFilter}
/>
);
})
customFilters
.sort((a, b) => a.label.localeCompare(b.label))
.map((customFilter) => {
return (
<CustomFilter
key={customFilter.id}
id={customFilter.id}
label={customFilter.label}
filters={customFilter.filters}
selectedFilterKey={selectedFilterKey}
isDeleting={isDeleting}
deleteError={deleteError}
dispatchSetFilter={dispatchSetFilter}
dispatchDeleteCustomFilter={dispatchDeleteCustomFilter}
onEditPress={onEditCustomFilter}
/>
);
})
}
<div className={styles.addButtonContainer}>

View File

@@ -12,18 +12,10 @@
.info {
color: var(--infoColor);
&:global(.darken) {
color: color(var(--infoColor) shade(30%));
}
}
.pink {
color: var(--pink);
&:global(.darken) {
color: color(var(--pink) shade(30%));
}
}
.success {

View File

@@ -18,7 +18,6 @@ class Icon extends PureComponent {
kind,
size,
title,
darken,
isSpinning,
...otherProps
} = this.props;
@@ -27,8 +26,7 @@ class Icon extends PureComponent {
<FontAwesomeIcon
className={classNames(
className,
styles[kind],
darken && 'darken'
styles[kind]
)}
icon={name}
spin={isSpinning}
@@ -61,7 +59,6 @@ Icon.propTypes = {
kind: PropTypes.string.isRequired,
size: PropTypes.number.isRequired,
title: PropTypes.oneOfType([PropTypes.string, PropTypes.func]),
darken: PropTypes.bool.isRequired,
isSpinning: PropTypes.bool.isRequired,
fixedWidth: PropTypes.bool.isRequired
};
@@ -69,7 +66,6 @@ Icon.propTypes = {
Icon.defaultProps = {
kind: kinds.DEFAULT,
size: 14,
darken: false,
isSpinning: false,
fixedWidth: false
};

View File

@@ -40,18 +40,26 @@ class FilterMenuContent extends Component {
}
{
customFilters.map((filter) => {
return (
<FilterMenuItem
key={filter.id}
filterKey={filter.id}
selectedFilterKey={selectedFilterKey}
onPress={onFilterSelect}
>
{filter.label}
</FilterMenuItem>
);
})
customFilters.length > 0 ?
<MenuItemSeparator /> :
null
}
{
customFilters
.sort((a, b) => a.label.localeCompare(b.label))
.map((filter) => {
return (
<FilterMenuItem
key={filter.id}
filterKey={filter.id}
selectedFilterKey={selectedFilterKey}
onPress={onFilterSelect}
>
{filter.label}
</FilterMenuItem>
);
})
}
{

View File

@@ -41,6 +41,9 @@ import {
faChevronCircleUp as fasChevronCircleUp,
faCircle as fasCircle,
faCircleDown as fasCircleDown,
faCirclePause as fasCirclePause,
faCirclePlay as fasCirclePlay,
faCircleStop as fasCircleStop,
faCloud as fasCloud,
faCloudDownloadAlt as fasCloudDownloadAlt,
faCog as fasCog,
@@ -55,6 +58,7 @@ import {
faEye as fasEye,
faFastBackward as fasFastBackward,
faFastForward as fasFastForward,
faFileCircleQuestion as fasFileCircleQuestion,
faFileExport as fasFileExport,
faFileInvoice as farFileInvoice,
faFilter as fasFilter,
@@ -146,7 +150,10 @@ export const EXPORT = fasFileExport;
export const EXTERNAL_LINK = fasExternalLinkAlt;
export const FATAL = fasTimesCircle;
export const FILE = farFile;
export const FILE_MISSING = fasFileCircleQuestion;
export const FILTER = fasFilter;
export const FINALE_SEASON = fasCirclePause;
export const FINALE_SERIES = fasCircleStop;
export const FOOTNOTE = fasAsterisk;
export const FOLDER = farFolder;
export const FOLDER_OPEN = fasFolderOpen;
@@ -178,6 +185,7 @@ export const PARENT = fasLevelUpAlt;
export const PARSE = fasCalculator;
export const PAUSED = fasPause;
export const PENDING = farClock;
export const PREMIERE = fasCirclePlay;
export const PROFILE = fasUser;
export const POSTER = fasTh;
export const QUEUED = fasCloud;

View File

@@ -269,33 +269,6 @@ function InteractiveImportModalContent(
const [interactiveImportErrorMessage, setInteractiveImportErrorMessage] =
useState<string | null>(null);
const [selectState, setSelectState] = useSelectState();
const [bulkSelectOptions, setBulkSelectOptions] = useState([
{
key: 'select',
value: translate('SelectDropdown'),
disabled: true,
},
{
key: 'season',
value: translate('SelectSeason'),
},
{
key: 'episode',
value: translate('SelectEpisodes'),
},
{
key: 'quality',
value: translate('SelectQuality'),
},
{
key: 'releaseGroup',
value: translate('SelectReleaseGroup'),
},
{
key: 'language',
value: translate('SelectLanguage'),
},
]);
const { allSelected, allUnselected, selectedState } = selectState;
const previousIsDeleting = usePrevious(isDeleting);
const dispatch = useDispatch();
@@ -318,19 +291,66 @@ function InteractiveImportModalContent(
return getSelectedIds(selectedState);
}, [selectedState]);
const bulkSelectOptions = useMemo(() => {
const { seasonSelectDisabled, episodeSelectDisabled } = items.reduce(
(acc, item) => {
if (!selectedIds.includes(item.id)) {
return acc;
}
acc.seasonSelectDisabled ||= !item.series;
acc.episodeSelectDisabled ||= !item.seasonNumber;
return acc;
},
{
seasonSelectDisabled: false,
episodeSelectDisabled: false,
}
);
const options = [
{
key: 'select',
value: translate('SelectDropdown'),
disabled: true,
},
{
key: 'season',
value: translate('SelectSeason'),
disabled: seasonSelectDisabled,
},
{
key: 'episode',
value: translate('SelectEpisodes'),
disabled: episodeSelectDisabled,
},
{
key: 'quality',
value: translate('SelectQuality'),
},
{
key: 'releaseGroup',
value: translate('SelectReleaseGroup'),
},
{
key: 'language',
value: translate('SelectLanguage'),
},
];
if (allowSeriesChange) {
options.splice(1, 0, {
key: 'series',
value: translate('SelectSeries'),
});
}
return options;
}, [allowSeriesChange, items, selectedIds]);
useEffect(
() => {
if (allowSeriesChange) {
const newBulkSelectOptions = [...bulkSelectOptions];
newBulkSelectOptions.splice(1, 0, {
key: 'series',
value: translate('SelectSeries'),
});
setBulkSelectOptions(newBulkSelectOptions);
}
if (initialSortKey) {
const sortProps: { sortKey: string; sortDirection?: string } = {
sortKey: initialSortKey,

View File

@@ -202,13 +202,18 @@ export default function SeriesIndexPosters(props: SeriesIndexPostersProps) {
if (current) {
const width = current.clientWidth;
const padding = bodyPadding - 5;
const finalWidth = width - padding * 2;
if (Math.abs(size.width - finalWidth) < 20 || size.width === finalWidth) {
return;
}
setSize({
width: width - padding * 2,
width: finalWidth,
height: window.innerHeight,
});
}
}, [isSmallScreen, scrollerRef, bounds]);
}, [isSmallScreen, size, scrollerRef, bounds]);
useEffect(() => {
const currentScrollerRef = scrollerRef.current as HTMLElement;

View File

@@ -133,7 +133,7 @@ class EditDownloadClientModalContent extends Component {
<FormInputGroup
type={inputTypes.NUMBER}
name="priority"
helpText={translate('PriorityHelpText')}
helpText={translate('DownloadClientPriorityHelpText')}
min={1}
max={50}
{...priority}

View File

@@ -149,7 +149,13 @@ export default {
delete selectedSchema.name;
selectedSchema.fields = selectedSchema.fields.map((field) => {
return { ...field };
const newField = { ...field };
if (newField.privacy === 'apiKey' || newField.privacy === 'password') {
newField.value = '';
}
return newField;
});
newState.selectedSchema = selectedSchema;

View File

@@ -158,6 +158,12 @@ export const defaultState = {
isSortable: true,
isVisible: true
},
{
name: 'added',
label: () => translate('Added'),
isSortable: true,
isVisible: false
},
{
name: 'progress',
label: () => translate('Progress'),

View File

@@ -1,8 +1,9 @@
import { createSelector } from 'reselect';
import AppState from 'App/State/AppState';
function createDimensionsSelector() {
return createSelector(
(state) => state.app.dimensions,
(state: AppState) => state.app.dimensions,
(dimensions) => {
return dimensions;
}

View File

@@ -213,6 +213,8 @@ module.exports = {
calendarTextDim: '#eee',
calendarTextDimAlternate: '#fff',
calendarFullColorFilter: 'grayscale(90%) contrast(200%) saturate(50%)',
//
// Table

View File

@@ -215,6 +215,8 @@ module.exports = {
calendarTextDim: '#666',
calendarTextDimAlternate: '#242424',
calendarFullColorFilter: 'brightness(30%)',
//
// Table

View File

@@ -28,6 +28,7 @@ interface Queue extends ModelBase {
sizeleft: number;
timeleft: string;
estimatedCompletionTime: string;
added?: string;
status: string;
trackedDownloadStatus: QueueTrackedDownloadStatus;
trackedDownloadState: QueueTrackedDownloadState;

View File

@@ -1,4 +1,5 @@
export interface UiSettings {
theme: string;
showRelativeDates: boolean;
shortDateFormat: string;
longDateFormat: string;

View File

@@ -131,6 +131,16 @@ namespace NzbDrone.Common.Test.Http
response.Content.Should().NotBeNullOrWhiteSpace();
}
[Test]
public void should_throw_timeout_request()
{
var request = new HttpRequest($"https://{_httpBinHost}/delay/10");
request.RequestTimeout = new TimeSpan(0, 0, 5);
Assert.ThrowsAsync<WebException>(async () => await Subject.ExecuteAsync(request));
}
[Test]
public async Task should_execute_https_get()
{

View File

@@ -102,31 +102,38 @@ namespace NzbDrone.Common.Http.Dispatchers
var httpClient = GetClient(request.Url);
using var responseMessage = await httpClient.SendAsync(requestMessage, HttpCompletionOption.ResponseHeadersRead, cts.Token);
try
{
byte[] data = null;
try
using var responseMessage = await httpClient.SendAsync(requestMessage, HttpCompletionOption.ResponseHeadersRead, cts.Token);
{
if (request.ResponseStream != null && responseMessage.StatusCode == HttpStatusCode.OK)
byte[] data = null;
try
{
await responseMessage.Content.CopyToAsync(request.ResponseStream, null, cts.Token);
if (request.ResponseStream != null && responseMessage.StatusCode == HttpStatusCode.OK)
{
await responseMessage.Content.CopyToAsync(request.ResponseStream, null, cts.Token);
}
else
{
data = await responseMessage.Content.ReadAsByteArrayAsync(cts.Token);
}
}
else
catch (Exception ex)
{
data = await responseMessage.Content.ReadAsByteArrayAsync(cts.Token);
throw new WebException("Failed to read complete http response", ex, WebExceptionStatus.ReceiveFailure, null);
}
var headers = responseMessage.Headers.ToNameValueCollection();
headers.Add(responseMessage.Content.Headers.ToNameValueCollection());
return new HttpResponse(request, new HttpHeader(headers), data, responseMessage.StatusCode, responseMessage.Version);
}
catch (Exception ex)
{
throw new WebException("Failed to read complete http response", ex, WebExceptionStatus.ReceiveFailure, null);
}
var headers = responseMessage.Headers.ToNameValueCollection();
headers.Add(responseMessage.Content.Headers.ToNameValueCollection());
return new HttpResponse(request, new HttpHeader(headers), data, responseMessage.StatusCode, responseMessage.Version);
}
catch (OperationCanceledException ex) when (cts.IsCancellationRequested)
{
throw new WebException("Http request timed out", ex.InnerException, WebExceptionStatus.Timeout, null);
}
}

View File

@@ -92,6 +92,10 @@ namespace NzbDrone.Common.Http
{
data = new XElement("base64", Convert.ToBase64String(bytes));
}
else if (value is Dictionary<string, string> d)
{
data = new XElement("struct", d.Select(p => new XElement("member", new XElement("name", p.Key), new XElement("value", p.Value))));
}
else
{
throw new InvalidOperationException($"Unhandled argument type {value.GetType().Name}");

View File

@@ -33,7 +33,7 @@ namespace NzbDrone.Core.Test.IndexerTests.FileListTests
Mocker.GetMock<IHttpClient>()
.Setup(o => o.ExecuteAsync(It.Is<HttpRequest>(v => v.Method == HttpMethod.Get)))
.Returns<HttpRequest>(r => Task.FromResult(new HttpResponse(r, new HttpHeader(), recentFeed)));
.Returns<HttpRequest>(r => Task.FromResult(new HttpResponse(r, new HttpHeader { { "Content-Type", "application/json" } }, recentFeed)));
var releases = await Subject.FetchRecent();

View File

@@ -23,7 +23,7 @@ namespace NzbDrone.Core.AutoTagging.Specifications
public override int Order => 1;
public override string ImplementationName => "Genre";
[FieldDefinition(1, Label = "Genre(s)", Type = FieldType.Tag)]
[FieldDefinition(1, Label = "AutoTaggingSpecificationGenre", Type = FieldType.Tag)]
public IEnumerable<string> Value { get; set; }
protected override bool IsSatisfiedByWithoutNegate(Series series)

View File

@@ -21,7 +21,7 @@ namespace NzbDrone.Core.AutoTagging.Specifications
public override int Order => 1;
public override string ImplementationName => "Original Language";
[FieldDefinition(1, Label = "Language", Type = FieldType.Select, SelectOptions = typeof(OriginalLanguageFieldConverter))]
[FieldDefinition(1, Label = "AutoTaggingSpecificationOriginalLanguage", Type = FieldType.Select, SelectOptions = typeof(OriginalLanguageFieldConverter))]
public int Value { get; set; }
protected override bool IsSatisfiedByWithoutNegate(Series series)

View File

@@ -20,7 +20,7 @@ namespace NzbDrone.Core.AutoTagging.Specifications
public override int Order => 1;
public override string ImplementationName => "Quality Profile";
[FieldDefinition(1, Label = "Quality Profile", Type = FieldType.QualityProfile)]
[FieldDefinition(1, Label = "AutoTaggingSpecificationQualityProfile", Type = FieldType.QualityProfile)]
public int Value { get; set; }
protected override bool IsSatisfiedByWithoutNegate(Series series)

View File

@@ -22,7 +22,7 @@ namespace NzbDrone.Core.AutoTagging.Specifications
public override int Order => 1;
public override string ImplementationName => "Root Folder";
[FieldDefinition(1, Label = "Root Folder", Type = FieldType.RootFolder)]
[FieldDefinition(1, Label = "AutoTaggingSpecificationRootFolder", Type = FieldType.RootFolder)]
public string Value { get; set; }
protected override bool IsSatisfiedByWithoutNegate(Series series)

View File

@@ -20,7 +20,7 @@ namespace NzbDrone.Core.AutoTagging.Specifications
public override int Order => 2;
public override string ImplementationName => "Series Type";
[FieldDefinition(1, Label = "Series Type", Type = FieldType.Select, SelectOptions = typeof(SeriesTypes))]
[FieldDefinition(1, Label = "AutoTaggingSpecificationSeriesType", Type = FieldType.Select, SelectOptions = typeof(SeriesTypes))]
public int Value { get; set; }
protected override bool IsSatisfiedByWithoutNegate(Series series)

View File

@@ -16,7 +16,7 @@ namespace NzbDrone.Core.AutoTagging.Specifications
public override int Order => 1;
public override string ImplementationName => "Status";
[FieldDefinition(1, Label = "Status", Type = FieldType.Select, SelectOptions = typeof(SeriesStatusType))]
[FieldDefinition(1, Label = "AutoTaggingSpecificationStatus", Type = FieldType.Select, SelectOptions = typeof(SeriesStatusType))]
public int Status { get; set; }
protected override bool IsSatisfiedByWithoutNegate(Series series)

View File

@@ -23,10 +23,10 @@ namespace NzbDrone.Core.AutoTagging.Specifications
public override int Order => 1;
public override string ImplementationName => "Year";
[FieldDefinition(1, Label = "Minimum Year", Type = FieldType.Number)]
[FieldDefinition(1, Label = "AutoTaggingSpecificationMinimumYear", Type = FieldType.Number)]
public int Min { get; set; }
[FieldDefinition(2, Label = "Maximum Year", Type = FieldType.Number)]
[FieldDefinition(2, Label = "AutoTaggingSpecificationMaximumYear", Type = FieldType.Number)]
public int Max { get; set; }
protected override bool IsSatisfiedByWithoutNegate(Series series)

View File

@@ -1,6 +1,7 @@
using System.Collections.Generic;
using System.IO;
using System.Linq;
using NLog;
using NzbDrone.Common.Extensions;
using NzbDrone.Core.Blocklisting;
using NzbDrone.Core.History;
@@ -23,10 +24,12 @@ namespace NzbDrone.Core.CustomFormats
public class CustomFormatCalculationService : ICustomFormatCalculationService
{
private readonly ICustomFormatService _formatService;
private readonly Logger _logger;
public CustomFormatCalculationService(ICustomFormatService formatService)
public CustomFormatCalculationService(ICustomFormatService formatService, Logger logger)
{
_formatService = formatService;
_logger = logger;
}
public List<CustomFormat> ParseCustomFormat(RemoteEpisode remoteEpisode, long size)
@@ -153,20 +156,23 @@ namespace NzbDrone.Core.CustomFormats
return matches.OrderBy(x => x.Name).ToList();
}
private static List<CustomFormat> ParseCustomFormat(EpisodeFile episodeFile, Series series, List<CustomFormat> allCustomFormats)
private List<CustomFormat> ParseCustomFormat(EpisodeFile episodeFile, Series series, List<CustomFormat> allCustomFormats)
{
var releaseTitle = string.Empty;
if (episodeFile.SceneName.IsNotNullOrWhiteSpace())
{
_logger.Trace("Using scene name for release title: {0}", episodeFile.SceneName);
releaseTitle = episodeFile.SceneName;
}
else if (episodeFile.OriginalFilePath.IsNotNullOrWhiteSpace())
{
_logger.Trace("Using original file path for release title: {0}", Path.GetFileName(episodeFile.OriginalFilePath));
releaseTitle = Path.GetFileName(episodeFile.OriginalFilePath);
}
else if (episodeFile.RelativePath.IsNotNullOrWhiteSpace())
{
_logger.Trace("Using relative path for release title: {0}", Path.GetFileName(episodeFile.RelativePath));
releaseTitle = Path.GetFileName(episodeFile.RelativePath);
}

View File

@@ -27,7 +27,7 @@ namespace NzbDrone.Core.CustomFormats
public override int Order => 3;
public override string ImplementationName => "Language";
[FieldDefinition(1, Label = "Language", Type = FieldType.Select, SelectOptions = typeof(LanguageFieldConverter))]
[FieldDefinition(1, Label = "CustomFormatsSpecificationLanguage", Type = FieldType.Select, SelectOptions = typeof(LanguageFieldConverter))]
public int Value { get; set; }
protected override bool IsSatisfiedByWithoutNegate(CustomFormatInput input)

View File

@@ -21,7 +21,7 @@ namespace NzbDrone.Core.CustomFormats
protected Regex _regex;
protected string _raw;
[FieldDefinition(1, Label = "Regular Expression", HelpText = "Custom Format RegEx is Case Insensitive")]
[FieldDefinition(1, Label = "CustomFormatsSpecificationRegularExpression", HelpText = "CustomFormatsSpecificationRegularExpressionHelpText")]
public string Value
{
get => _raw;

View File

@@ -20,7 +20,7 @@ namespace NzbDrone.Core.CustomFormats
public override int Order => 6;
public override string ImplementationName => "Resolution";
[FieldDefinition(1, Label = "Resolution", Type = FieldType.Select, SelectOptions = typeof(Resolution))]
[FieldDefinition(1, Label = "CustomFormatsSpecificationResolution", Type = FieldType.Select, SelectOptions = typeof(Resolution))]
public int Value { get; set; }
protected override bool IsSatisfiedByWithoutNegate(CustomFormatInput input)

View File

@@ -20,10 +20,10 @@ namespace NzbDrone.Core.CustomFormats
public override int Order => 8;
public override string ImplementationName => "Size";
[FieldDefinition(1, Label = "Minimum Size", HelpText = "Release must be greater than this size", Unit = "GB", Type = FieldType.Number)]
[FieldDefinition(1, Label = "CustomFormatsSpecificationMinimumSize", HelpText = "CustomFormatsSpecificationMinimumSizeHelpText", Unit = "GB", Type = FieldType.Number)]
public double Min { get; set; }
[FieldDefinition(1, Label = "Maximum Size", HelpText = "Release must be less than or equal to this size", Unit = "GB", Type = FieldType.Number)]
[FieldDefinition(1, Label = "CustomFormatsSpecificationMaximumSize", HelpText = "CustomFormatsSpecificationMaximumSizeHelpText", Unit = "GB", Type = FieldType.Number)]
public double Max { get; set; }
protected override bool IsSatisfiedByWithoutNegate(CustomFormatInput input)

View File

@@ -20,7 +20,7 @@ namespace NzbDrone.Core.CustomFormats
public override int Order => 5;
public override string ImplementationName => "Source";
[FieldDefinition(1, Label = "Source", Type = FieldType.Select, SelectOptions = typeof(QualitySource))]
[FieldDefinition(1, Label = "CustomFormatsSpecificationSource", Type = FieldType.Select, SelectOptions = typeof(QualitySource))]
public int Value { get; set; }
protected override bool IsSatisfiedByWithoutNegate(CustomFormatInput input)

View File

@@ -8,6 +8,8 @@ namespace NzbDrone.Core.Datastore.Migration
{
protected override void MainDbUpgrade()
{
Delete.FromTable("Commands").AllRows();
Alter.Table("Blocklist").AlterColumn("Date").AsDateTimeOffset().NotNullable();
Alter.Table("Blocklist").AlterColumn("PublishedDate").AsDateTimeOffset().Nullable();
Alter.Table("Commands").AlterColumn("QueuedAt").AsDateTimeOffset().NotNullable();

View File

@@ -2,6 +2,7 @@ using System.Collections.Generic;
using System.Linq;
using System.Xml.Linq;
using System.Xml.XPath;
using NzbDrone.Common.Extensions;
using NzbDrone.Common.Http;
using NzbDrone.Core.Download.Extensions;
@@ -97,8 +98,14 @@ namespace NzbDrone.Core.Download.Clients.Aria2
public string AddMagnet(Aria2Settings settings, string magnet)
{
var response = ExecuteRequest(settings, "aria2.addUri", GetToken(settings), new List<string> { magnet });
var options = new Dictionary<string, string>();
if (settings.Directory.IsNotNullOrWhiteSpace())
{
options.Add("dir", settings.Directory);
}
var response = ExecuteRequest(settings, "aria2.addUri", GetToken(settings), new List<string> { magnet }, options);
var gid = response.GetStringResponse();
return gid;
@@ -106,8 +113,16 @@ namespace NzbDrone.Core.Download.Clients.Aria2
public string AddTorrent(Aria2Settings settings, byte[] torrent)
{
var response = ExecuteRequest(settings, "aria2.addTorrent", GetToken(settings), torrent);
// Aria2's second parameter is an array of URIs and needs to be sent if options are provided, this satisfies that requirement.
var emptyListOfUris = new List<string>();
var options = new Dictionary<string, string>();
if (settings.Directory.IsNotNullOrWhiteSpace())
{
options.Add("dir", settings.Directory);
}
var response = ExecuteRequest(settings, "aria2.addTorrent", GetToken(settings), torrent, emptyListOfUris, options);
var gid = response.GetStringResponse();
return gid;

View File

@@ -41,6 +41,9 @@ namespace NzbDrone.Core.Download.Clients.Aria2
[FieldDefinition(4, Label = "SecretToken", Type = FieldType.Password, Privacy = PrivacyLevel.Password)]
public string SecretToken { get; set; }
[FieldDefinition(5, Label = "Directory", Type = FieldType.Textbox, HelpText = "DownloadClientAriaSettingsDirectoryHelpText")]
public string Directory { get; set; }
public NzbDroneValidationResult Validate()
{
return new NzbDroneValidationResult(Validator.Validate(this));

View File

@@ -620,7 +620,7 @@ namespace NzbDrone.Core.Download.Clients.QBittorrent
}
else if (torrent.RatioLimit == -2 && config.MaxRatioEnabled)
{
if (torrent.Ratio >= config.MaxRatio)
if (Math.Round(torrent.Ratio, 2) >= config.MaxRatio)
{
return true;
}

View File

@@ -368,6 +368,7 @@ namespace NzbDrone.Core.Download.Pending
RemoteEpisode = pendingRelease.RemoteEpisode,
Timeleft = timeleft,
EstimatedCompletionTime = ect,
Added = pendingRelease.Added,
Status = pendingRelease.Reason.ToString(),
Protocol = pendingRelease.RemoteEpisode.Release.DownloadProtocol,
Indexer = pendingRelease.RemoteEpisode.Release.Indexer

View File

@@ -225,9 +225,7 @@ namespace NzbDrone.Core.Download
}
catch (FormatException ex)
{
_logger.Error(ex, "Failed to parse magnetlink for episode '{0}': '{1}'", remoteEpisode.Release.Title, magnetUrl);
return null;
throw new ReleaseDownloadException(remoteEpisode.Release, "Failed to parse magnetlink for episode '{0}': '{1}'", ex, remoteEpisode.Release.Title, magnetUrl);
}
if (hash != null)

View File

@@ -15,6 +15,7 @@ namespace NzbDrone.Core.Download.TrackedDownloads
public TrackedDownloadStatusMessage[] StatusMessages { get; private set; }
public DownloadProtocol Protocol { get; set; }
public string Indexer { get; set; }
public DateTime? Added { get; set; }
public bool IsTrackable { get; set; }
public bool HasNotifiedManualInteractionRequired { get; set; }

View File

@@ -135,6 +135,7 @@ namespace NzbDrone.Core.Download.TrackedDownloads
var grabbedEvent = historyItems.FirstOrDefault(v => v.EventType == EpisodeHistoryEventType.Grabbed);
trackedDownload.Indexer = grabbedEvent?.Data["indexer"];
trackedDownload.Added = grabbedEvent?.Date;
if (parsedEpisodeInfo == null ||
trackedDownload.RemoteEpisode == null ||

View File

@@ -18,7 +18,7 @@ namespace NzbDrone.Core.Extras.Metadata.Consumers.Plex
SeriesPlexMatchFile = true;
}
[FieldDefinition(0, Label = "Series Plex Match File", Type = FieldType.Checkbox, Section = MetadataSectionType.Metadata, HelpText = "Creates a .plexmatch file in the series folder")]
[FieldDefinition(0, Label = "MetadataPlexSettingsSeriesPlexMatchFile", Type = FieldType.Checkbox, Section = MetadataSectionType.Metadata, HelpText = "MetadataPlexSettingsSeriesPlexMatchFileHelpText")]
public bool SeriesPlexMatchFile { get; set; }
public NzbDroneValidationResult Validate()

View File

@@ -21,16 +21,16 @@ namespace NzbDrone.Core.Extras.Metadata.Consumers.Roksbox
EpisodeImages = true;
}
[FieldDefinition(0, Label = "Episode Metadata", Type = FieldType.Checkbox, Section = MetadataSectionType.Metadata, HelpText = "Season##\\filename.xml")]
[FieldDefinition(0, Label = "MetadataSettingsEpisodeMetadata", Type = FieldType.Checkbox, Section = MetadataSectionType.Metadata, HelpText = "Season##\\filename.xml")]
public bool EpisodeMetadata { get; set; }
[FieldDefinition(1, Label = "Series Images", Type = FieldType.Checkbox, Section = MetadataSectionType.Image, HelpText = "Series Title.jpg")]
[FieldDefinition(1, Label = "MetadataSettingsSeriesImages", Type = FieldType.Checkbox, Section = MetadataSectionType.Image, HelpText = "Series Title.jpg")]
public bool SeriesImages { get; set; }
[FieldDefinition(2, Label = "Season Images", Type = FieldType.Checkbox, Section = MetadataSectionType.Image, HelpText = "Season ##.jpg")]
[FieldDefinition(2, Label = "MetadataSettingsSeasonImages", Type = FieldType.Checkbox, Section = MetadataSectionType.Image, HelpText = "Season ##.jpg")]
public bool SeasonImages { get; set; }
[FieldDefinition(3, Label = "Episode Images", Type = FieldType.Checkbox, Section = MetadataSectionType.Image, HelpText = "Season##\\filename.jpg")]
[FieldDefinition(3, Label = "MetadataSettingsEpisodeImages", Type = FieldType.Checkbox, Section = MetadataSectionType.Image, HelpText = "Season##\\filename.jpg")]
public bool EpisodeImages { get; set; }
public bool IsValid => true;

View File

@@ -21,16 +21,16 @@ namespace NzbDrone.Core.Extras.Metadata.Consumers.Wdtv
EpisodeImages = true;
}
[FieldDefinition(0, Label = "Episode Metadata", Type = FieldType.Checkbox, Section = MetadataSectionType.Metadata, HelpText = "Season##\\filename.xml")]
[FieldDefinition(0, Label = "MetadataSettingsEpisodeMetadata", Type = FieldType.Checkbox, Section = MetadataSectionType.Metadata, HelpText = "Season##\\filename.xml")]
public bool EpisodeMetadata { get; set; }
[FieldDefinition(1, Label = "Series Images", Type = FieldType.Checkbox, Section = MetadataSectionType.Image, HelpText = "folder.jpg")]
[FieldDefinition(1, Label = "MetadataSettingsSeriesImages", Type = FieldType.Checkbox, Section = MetadataSectionType.Image, HelpText = "folder.jpg")]
public bool SeriesImages { get; set; }
[FieldDefinition(2, Label = "Season Images", Type = FieldType.Checkbox, Section = MetadataSectionType.Image, HelpText = "Season##\\folder.jpg")]
[FieldDefinition(2, Label = "MetadataSettingsSeasonImages", Type = FieldType.Checkbox, Section = MetadataSectionType.Image, HelpText = "Season##\\folder.jpg")]
public bool SeasonImages { get; set; }
[FieldDefinition(3, Label = "Episode Images", Type = FieldType.Checkbox, Section = MetadataSectionType.Image, HelpText = "Season##\\filename.metathumb")]
[FieldDefinition(3, Label = "MetadataSettingsEpisodeImages", Type = FieldType.Checkbox, Section = MetadataSectionType.Image, HelpText = "Season##\\filename.metathumb")]
public bool EpisodeImages { get; set; }
public bool IsValid => true;

View File

@@ -24,28 +24,28 @@ namespace NzbDrone.Core.Extras.Metadata.Consumers.Xbmc
EpisodeImages = true;
}
[FieldDefinition(0, Label = "Series Metadata", Type = FieldType.Checkbox, Section = MetadataSectionType.Metadata, HelpText = "tvshow.nfo with full series metadata")]
[FieldDefinition(0, Label = "MetadataSettingsSeriesMetadata", Type = FieldType.Checkbox, Section = MetadataSectionType.Metadata, HelpText = "MetadataXmbcSettingsSeriesMetadataHelpText")]
public bool SeriesMetadata { get; set; }
[FieldDefinition(1, Label = "Series Metadata Episode Guide", Type = FieldType.Checkbox, Section = MetadataSectionType.Metadata, HelpText = "Include JSON formatted episode guide element in tvshow.nfo (Requires 'Series Metadata')", Advanced = true)]
[FieldDefinition(1, Label = "MetadataSettingsSeriesMetadataEpisodeGuide", Type = FieldType.Checkbox, Section = MetadataSectionType.Metadata, HelpText = "MetadataXmbcSettingsSeriesMetadataEpisodeGuideHelpText", Advanced = true)]
public bool SeriesMetadataEpisodeGuide { get; set; }
[FieldDefinition(2, Label = "Series Metadata URL", Type = FieldType.Checkbox, Section = MetadataSectionType.Metadata, HelpText = "Include TheTVDB show URL in tvshow.nfo (can be combined with 'Series Metadata')", Advanced = true)]
[FieldDefinition(2, Label = "MetadataSettingsSeriesMetadataUrl", Type = FieldType.Checkbox, Section = MetadataSectionType.Metadata, HelpText = "MetadataXmbcSettingsSeriesMetadataUrlHelpText", Advanced = true)]
public bool SeriesMetadataUrl { get; set; }
[FieldDefinition(3, Label = "Episode Metadata", Type = FieldType.Checkbox, Section = MetadataSectionType.Metadata, HelpText = "<filename>.nfo")]
[FieldDefinition(3, Label = "MetadataSettingsEpisodeMetadata", Type = FieldType.Checkbox, Section = MetadataSectionType.Metadata, HelpText = "<filename>.nfo")]
public bool EpisodeMetadata { get; set; }
[FieldDefinition(4, Label = "Episode Metadata Image Thumbs", Type = FieldType.Checkbox, Section = MetadataSectionType.Image, HelpText = "Include image thumb tags in <filename>.nfo (Requires 'Episode Metadata')", Advanced = true)]
[FieldDefinition(4, Label = "MetadataSettingsEpisodeMetadataImageThumbs", Type = FieldType.Checkbox, Section = MetadataSectionType.Image, HelpText = "MetadataXmbcSettingsEpisodeMetadataImageThumbsHelpText", Advanced = true)]
public bool EpisodeImageThumb { get; set; }
[FieldDefinition(5, Label = "Series Images", Type = FieldType.Checkbox, Section = MetadataSectionType.Image, HelpText = "fanart.jpg, poster.jpg, banner.jpg")]
[FieldDefinition(5, Label = "MetadataSettingsSeriesImages", Type = FieldType.Checkbox, Section = MetadataSectionType.Image, HelpText = "fanart.jpg, poster.jpg, banner.jpg")]
public bool SeriesImages { get; set; }
[FieldDefinition(6, Label = "Season Images", Type = FieldType.Checkbox, Section = MetadataSectionType.Image, HelpText = "season##-poster.jpg, season##-banner.jpg, season-specials-poster.jpg, season-specials-banner.jpg")]
[FieldDefinition(6, Label = "MetadataSettingsSeasonImages", Type = FieldType.Checkbox, Section = MetadataSectionType.Image, HelpText = "season##-poster.jpg, season##-banner.jpg, season-specials-poster.jpg, season-specials-banner.jpg")]
public bool SeasonImages { get; set; }
[FieldDefinition(7, Label = "Episode Images", Type = FieldType.Checkbox, Section = MetadataSectionType.Image, HelpText = "<filename>-thumb.jpg")]
[FieldDefinition(7, Label = "MetadataSettingsEpisodeImages", Type = FieldType.Checkbox, Section = MetadataSectionType.Image, HelpText = "<filename>-thumb.jpg")]
public bool EpisodeImages { get; set; }
public bool IsValid => true;

View File

@@ -124,22 +124,20 @@ namespace NzbDrone.Core.History
public PagingSpec<EpisodeHistory> GetPaged(PagingSpec<EpisodeHistory> pagingSpec, int[] languages, int[] qualities)
{
pagingSpec.Records = GetPagedRecords(PagedBuilder(pagingSpec, languages, qualities), pagingSpec, PagedQuery);
pagingSpec.Records = GetPagedRecords(PagedBuilder(languages, qualities), pagingSpec, PagedQuery);
var countTemplate = $"SELECT COUNT(*) FROM (SELECT /**select**/ FROM \"{TableMapping.Mapper.TableNameMapping(typeof(EpisodeHistory))}\" /**join**/ /**innerjoin**/ /**leftjoin**/ /**where**/ /**groupby**/ /**having**/) AS \"Inner\"";
pagingSpec.TotalRecords = GetPagedRecordCount(PagedBuilder(pagingSpec, languages, qualities).Select(typeof(EpisodeHistory)), pagingSpec, countTemplate);
pagingSpec.TotalRecords = GetPagedRecordCount(PagedBuilder(languages, qualities).Select(typeof(EpisodeHistory)), pagingSpec, countTemplate);
return pagingSpec;
}
private SqlBuilder PagedBuilder(PagingSpec<EpisodeHistory> pagingSpec, int[] languages, int[] qualities)
private SqlBuilder PagedBuilder(int[] languages, int[] qualities)
{
var builder = Builder()
.Join<EpisodeHistory, Series>((h, a) => h.SeriesId == a.Id)
.Join<EpisodeHistory, Episode>((h, a) => h.EpisodeId == a.Id);
AddFilters(builder, pagingSpec);
if (languages is { Length: > 0 })
{
builder.Where($"({BuildLanguageWhereClause(languages)})");

View File

@@ -3,6 +3,7 @@ using System.Collections.Generic;
using NLog;
using NzbDrone.Common.Http;
using NzbDrone.Core.Configuration;
using NzbDrone.Core.Localization;
using NzbDrone.Core.Parser;
using NzbDrone.Core.Parser.Model;
using NzbDrone.Core.Validation;
@@ -28,8 +29,9 @@ namespace NzbDrone.Core.ImportLists.AniList
IImportListStatusService importListStatusService,
IConfigService configService,
IParsingService parsingService,
ILocalizationService localizationService,
Logger logger)
: base(httpClient, importListStatusService, configService, parsingService, logger)
: base(httpClient, importListStatusService, configService, parsingService, localizationService, logger)
{
_importListRepository = netImportRepository;
}

View File

@@ -42,16 +42,16 @@ namespace NzbDrone.Core.ImportLists.AniList
public string BaseUrl { get; set; }
[FieldDefinition(0, Label = "Access Token", Type = FieldType.Textbox, Hidden = HiddenType.Hidden)]
[FieldDefinition(0, Label = "ImportListsSettingsAccessToken", Type = FieldType.Textbox, Hidden = HiddenType.Hidden)]
public string AccessToken { get; set; }
[FieldDefinition(0, Label = "Refresh Token", Type = FieldType.Textbox, Hidden = HiddenType.Hidden)]
[FieldDefinition(0, Label = "ImportListsSettingsRefreshToken", Type = FieldType.Textbox, Hidden = HiddenType.Hidden)]
public string RefreshToken { get; set; }
[FieldDefinition(0, Label = "Expires", Type = FieldType.Textbox, Hidden = HiddenType.Hidden)]
[FieldDefinition(0, Label = "ImportListsSettingsExpires", Type = FieldType.Textbox, Hidden = HiddenType.Hidden)]
public DateTime Expires { get; set; }
[FieldDefinition(99, Label = "Authenticate with AniList", Type = FieldType.OAuth)]
[FieldDefinition(99, Label = "ImportListsAniListSettingsAuthenticateWithAniList", Type = FieldType.OAuth)]
public string SignIn { get; set; }
public NzbDroneValidationResult Validate()

View File

@@ -9,6 +9,7 @@ using NzbDrone.Core.Configuration;
using NzbDrone.Core.Http.CloudFlare;
using NzbDrone.Core.ImportLists.Exceptions;
using NzbDrone.Core.Indexers.Exceptions;
using NzbDrone.Core.Localization;
using NzbDrone.Core.Parser;
using NzbDrone.Core.Parser.Model;
@@ -21,12 +22,13 @@ namespace NzbDrone.Core.ImportLists.AniList.List
IImportListStatusService importListStatusService,
IConfigService configService,
IParsingService parsingService,
ILocalizationService localizationService,
Logger logger)
: base(netImportRepository, httpClient, importListStatusService, configService, parsingService, logger)
: base(netImportRepository, httpClient, importListStatusService, configService, parsingService, localizationService, logger)
{
}
public override string Name => "AniList List";
public override string Name => _localizationService.GetLocalizedString("TypeOfList", new Dictionary<string, object> { { "typeOfList", "AniList" } });
public override AniListRequestGenerator GetRequestGenerator()
{

View File

@@ -31,40 +31,40 @@ namespace NzbDrone.Core.ImportLists.AniList.List
protected override AbstractValidator<AniListSettings> Validator => new AniListSettingsValidator();
[FieldDefinition(1, Label = "Username", HelpText = "Username for the List to import from")]
[FieldDefinition(1, Label = "Username", HelpText = "ImportListsAniListSettingsUsernameHelpText")]
public string Username { get; set; }
[FieldDefinition(2, Label = "Import Watching", Type = FieldType.Checkbox, Section = sectionImport, HelpText = "List: Currently Watching")]
[FieldDefinition(2, Label = "ImportListsAniListSettingsImportWatching", Type = FieldType.Checkbox, Section = sectionImport, HelpText = "ImportListsAniListSettingsImportWatchingHelpText")]
public bool ImportCurrent { get; set; }
[FieldDefinition(3, Label = "Import Planning", Type = FieldType.Checkbox, Section = sectionImport, HelpText = "List: Planning to Watch")]
[FieldDefinition(3, Label = "ImportListsAniListSettingsImportPlanning", Type = FieldType.Checkbox, Section = sectionImport, HelpText = "ImportListsAniListSettingsImportPlanningHelpText")]
public bool ImportPlanning { get; set; }
[FieldDefinition(4, Label = "Import Completed", Type = FieldType.Checkbox, Section = sectionImport, HelpText = "List: Completed Watching")]
[FieldDefinition(4, Label = "ImportListsAniListSettingsImportCompleted", Type = FieldType.Checkbox, Section = sectionImport, HelpText = "ImportListsAniListSettingsImportCompletedHelpText")]
public bool ImportCompleted { get; set; }
[FieldDefinition(5, Label = "Import Dropped", Type = FieldType.Checkbox, Section = sectionImport, HelpText = "List: Dropped")]
[FieldDefinition(5, Label = "ImportListsAniListSettingsImportDropped", Type = FieldType.Checkbox, Section = sectionImport, HelpText = "ImportListsAniListSettingsImportDroppedHelpText")]
public bool ImportDropped { get; set; }
[FieldDefinition(6, Label = "Import Paused", Type = FieldType.Checkbox, Section = sectionImport, HelpText = "List: On Hold")]
[FieldDefinition(6, Label = "ImportListsAniListSettingsImportPaused", Type = FieldType.Checkbox, Section = sectionImport, HelpText = "ImportListsAniListSettingsImportPausedHelpText")]
public bool ImportPaused { get; set; }
[FieldDefinition(7, Label = "Import Repeating", Type = FieldType.Checkbox, Section = sectionImport, HelpText = "List: Currently Rewatching")]
[FieldDefinition(7, Label = "ImportListsAniListSettingsImportRepeating", Type = FieldType.Checkbox, Section = sectionImport, HelpText = "ImportListsAniListSettingsImportRepeatingHelpText")]
public bool ImportRepeating { get; set; }
[FieldDefinition(8, Label = "Import Finished", Type = FieldType.Checkbox, Section = sectionImport, HelpText = "Media: All episodes have aired")]
[FieldDefinition(8, Label = "ImportListsAniListSettingsImportFinished", Type = FieldType.Checkbox, Section = sectionImport, HelpText = "ImportListsAniListSettingsImportFinishedHelpText")]
public bool ImportFinished { get; set; }
[FieldDefinition(9, Label = "Import Releasing", Type = FieldType.Checkbox, Section = sectionImport, HelpText = "Media: Currently airing new episodes")]
[FieldDefinition(9, Label = "ImportListsAniListSettingsImportReleasing", Type = FieldType.Checkbox, Section = sectionImport, HelpText = "ImportListsAniListSettingsImportReleasingHelpText")]
public bool ImportReleasing { get; set; }
[FieldDefinition(10, Label = "Import Not Yet Released", Type = FieldType.Checkbox, Section = sectionImport, HelpText = "Media: Airing has not yet started")]
[FieldDefinition(10, Label = "ImportListsAniListSettingsImportNotYetReleased", Type = FieldType.Checkbox, Section = sectionImport, HelpText = "ImportListsAniListSettingsImportNotYetReleasedHelpText")]
public bool ImportUnreleased { get; set; }
[FieldDefinition(11, Label = "Import Cancelled", Type = FieldType.Checkbox, Section = sectionImport, HelpText = "Media: Series is cancelled")]
[FieldDefinition(11, Label = "ImportListsAniListSettingsImportCancelled", Type = FieldType.Checkbox, Section = sectionImport, HelpText = "ImportListsAniListSettingsImportCancelledHelpText")]
public bool ImportCancelled { get; set; }
[FieldDefinition(12, Label = "Import Hiatus", Type = FieldType.Checkbox, Section = sectionImport, HelpText = "Media: Series on Hiatus")]
[FieldDefinition(12, Label = "ImportListsAniListSettingsImportHiatus", Type = FieldType.Checkbox, Section = sectionImport, HelpText = "ImportListsAniListSettingsImportHiatusHelpText")]
public bool ImportHiatus { get; set; }
}
}

View File

@@ -4,6 +4,7 @@ using FluentValidation.Results;
using NLog;
using NzbDrone.Common.Extensions;
using NzbDrone.Core.Configuration;
using NzbDrone.Core.Localization;
using NzbDrone.Core.Parser;
using NzbDrone.Core.Parser.Model;
@@ -12,7 +13,7 @@ namespace NzbDrone.Core.ImportLists.Custom
public class CustomImport : ImportListBase<CustomSettings>
{
private readonly ICustomImportProxy _customProxy;
public override string Name => "Custom List";
public override string Name => _localizationService.GetLocalizedString("ImportListsCustomListSettingsName");
public override TimeSpan MinRefreshInterval => TimeSpan.FromHours(6);
@@ -22,8 +23,9 @@ namespace NzbDrone.Core.ImportLists.Custom
IImportListStatusService importListStatusService,
IConfigService configService,
IParsingService parsingService,
ILocalizationService localizationService,
Logger logger)
: base(importListStatusService, configService, parsingService, logger)
: base(importListStatusService, configService, parsingService, localizationService, logger)
{
_customProxy = customProxy;
}

View File

@@ -10,6 +10,7 @@ using NLog;
using NzbDrone.Common.Extensions;
using NzbDrone.Common.Http;
using NzbDrone.Core.Localization;
namespace NzbDrone.Core.ImportLists.Custom
{
@@ -22,11 +23,13 @@ namespace NzbDrone.Core.ImportLists.Custom
public class CustomImportProxy : ICustomImportProxy
{
private readonly IHttpClient _httpClient;
private readonly ILocalizationService _localizationService;
private readonly Logger _logger;
public CustomImportProxy(IHttpClient httpClient, Logger logger)
public CustomImportProxy(IHttpClient httpClient, ILocalizationService localizationService, Logger logger)
{
_httpClient = httpClient;
_localizationService = localizationService;
_logger = logger;
}
@@ -46,16 +49,16 @@ namespace NzbDrone.Core.ImportLists.Custom
if (ex.Response.StatusCode == HttpStatusCode.Unauthorized)
{
_logger.Error(ex, "There was an authorization issue. We cannot get the list from the provider.");
return new ValidationFailure("BaseUrl", "It seems we are unauthorized to make this request.");
return new ValidationFailure("BaseUrl", _localizationService.GetLocalizedString("ImportListsCustomListValidationAuthenticationFailure"));
}
_logger.Error(ex, "Unable to connect to import list.");
return new ValidationFailure("BaseUrl", $"We are unable to make the request to that URL. StatusCode: {ex.Response.StatusCode}");
return new ValidationFailure("BaseUrl", _localizationService.GetLocalizedString("ImportListsCustomListValidationConnectionError", new Dictionary<string, object> { { "exceptionStatusCode", ex.Response.StatusCode } }));
}
catch (Exception ex)
{
_logger.Error(ex, "Unable to connect to import list.");
return new ValidationFailure(string.Empty, $"Unable to connect to import list: {ex.Message}. Check the log surrounding this error for details.");
return new ValidationFailure(string.Empty, _localizationService.GetLocalizedString("ImportListsValidationUnableToConnectException", new Dictionary<string, object> { { "exceptionMessage", ex.Message } }));
}
return null;

View File

@@ -22,7 +22,7 @@ namespace NzbDrone.Core.ImportLists.Custom
BaseUrl = "";
}
[FieldDefinition(0, Label = "List URL", HelpText = "The URL for the series list")]
[FieldDefinition(0, Label = "ImportListsCustomListSettingsUrl", HelpText = "ImportListsCustomListSettingsUrlHelpText")]
public string BaseUrl { get; set; }
public NzbDroneValidationResult Validate()

View File

@@ -10,6 +10,7 @@ using NzbDrone.Core.Configuration;
using NzbDrone.Core.Http.CloudFlare;
using NzbDrone.Core.ImportLists.Exceptions;
using NzbDrone.Core.Indexers.Exceptions;
using NzbDrone.Core.Localization;
using NzbDrone.Core.Parser;
using NzbDrone.Core.Parser.Model;
using NzbDrone.Core.Validation;
@@ -31,8 +32,8 @@ namespace NzbDrone.Core.ImportLists
public abstract IImportListRequestGenerator GetRequestGenerator();
public abstract IParseImportListResponse GetParser();
public HttpImportListBase(IHttpClient httpClient, IImportListStatusService importListStatusService, IConfigService configService, IParsingService parsingService, Logger logger)
: base(importListStatusService, configService, parsingService, logger)
public HttpImportListBase(IHttpClient httpClient, IImportListStatusService importListStatusService, IConfigService configService, IParsingService parsingService, ILocalizationService localizationService, Logger logger)
: base(importListStatusService, configService, parsingService, localizationService, logger)
{
_httpClient = httpClient;
}

View File

@@ -3,6 +3,7 @@ using System.Collections.Generic;
using NLog;
using NzbDrone.Common.Http;
using NzbDrone.Core.Configuration;
using NzbDrone.Core.Localization;
using NzbDrone.Core.Parser;
using NzbDrone.Core.ThingiProvider;
@@ -10,7 +11,7 @@ namespace NzbDrone.Core.ImportLists.Imdb
{
public class ImdbListImport : HttpImportListBase<ImdbListSettings>
{
public override string Name => "IMDb Lists";
public override string Name => _localizationService.GetLocalizedString("TypeOfList", new Dictionary<string, object> { { "typeOfList", "IMDb" } });
public override ImportListType ListType => ImportListType.Other;
public override TimeSpan MinRefreshInterval => TimeSpan.FromHours(12);
@@ -19,8 +20,9 @@ namespace NzbDrone.Core.ImportLists.Imdb
IImportListStatusService importListStatusService,
IConfigService configService,
IParsingService parsingService,
ILocalizationService localizationService,
Logger logger)
: base(httpClient, importListStatusService, configService, parsingService, logger)
: base(httpClient, importListStatusService, configService, parsingService, localizationService, logger)
{
}

View File

@@ -20,7 +20,7 @@ namespace NzbDrone.Core.ImportLists.Imdb
public string BaseUrl { get; set; }
[FieldDefinition(1, Label = "List ID", HelpText = "IMDb list ID (e.g ls12345678)")]
[FieldDefinition(1, Label = "ImportListsImdbSettingsListId", HelpText = "ImportListsImdbSettingsListIdHelpText")]
public string ListId { get; set; }
public NzbDroneValidationResult Validate()

View File

@@ -4,6 +4,7 @@ using System.Linq;
using FluentValidation.Results;
using NLog;
using NzbDrone.Core.Configuration;
using NzbDrone.Core.Localization;
using NzbDrone.Core.Parser;
using NzbDrone.Core.Parser.Model;
using NzbDrone.Core.ThingiProvider;
@@ -16,6 +17,7 @@ namespace NzbDrone.Core.ImportLists
protected readonly IImportListStatusService _importListStatusService;
protected readonly IConfigService _configService;
protected readonly IParsingService _parsingService;
protected readonly ILocalizationService _localizationService;
protected readonly Logger _logger;
public abstract string Name { get; }
@@ -24,11 +26,12 @@ namespace NzbDrone.Core.ImportLists
public abstract TimeSpan MinRefreshInterval { get; }
public ImportListBase(IImportListStatusService importListStatusService, IConfigService configService, IParsingService parsingService, Logger logger)
public ImportListBase(IImportListStatusService importListStatusService, IConfigService configService, IParsingService parsingService, ILocalizationService localizationService, Logger logger)
{
_importListStatusService = importListStatusService;
_configService = configService;
_parsingService = parsingService;
_localizationService = localizationService;
_logger = logger;
}
@@ -86,7 +89,7 @@ namespace NzbDrone.Core.ImportLists
catch (Exception ex)
{
_logger.Error(ex, "Test aborted due to exception");
failures.Add(new ValidationFailure(string.Empty, "Test was aborted due to an error: " + ex.Message));
failures.Add(new ValidationFailure(string.Empty, _localizationService.GetLocalizedString("ImportListsValidationTestFailed", new Dictionary<string, object> { { "exceptionMessage", ex.Message } })));
}
return new ValidationResult(failures);

View File

@@ -5,6 +5,7 @@ using NzbDrone.Common.Extensions;
using NzbDrone.Common.Http;
using NzbDrone.Core.Configuration;
using NzbDrone.Core.Exceptions;
using NzbDrone.Core.Localization;
using NzbDrone.Core.Notifications.Plex.PlexTv;
using NzbDrone.Core.Parser;
using NzbDrone.Core.Parser.Model;
@@ -24,13 +25,14 @@ namespace NzbDrone.Core.ImportLists.Plex
IImportListStatusService importListStatusService,
IConfigService configService,
IParsingService parsingService,
ILocalizationService localizationService,
Logger logger)
: base(httpClient, importListStatusService, configService, parsingService, logger)
: base(httpClient, importListStatusService, configService, parsingService, localizationService, logger)
{
_plexTvService = plexTvService;
}
public override string Name => "Plex Watchlist";
public override string Name => _localizationService.GetLocalizedString("ImportListsPlexSettingsWatchlistName");
public override int PageSize => 50;
public override IList<ImportListItemInfo> Fetch()

View File

@@ -27,10 +27,10 @@ namespace NzbDrone.Core.ImportLists.Plex
public string BaseUrl { get; set; }
[FieldDefinition(0, Label = "Access Token", Type = FieldType.Textbox, Hidden = HiddenType.Hidden)]
[FieldDefinition(0, Label = "ImportListsSettingsAccessToken", Type = FieldType.Textbox, Hidden = HiddenType.Hidden)]
public string AccessToken { get; set; }
[FieldDefinition(99, Label = "Authenticate with Plex.tv", Type = FieldType.OAuth)]
[FieldDefinition(99, Label = "ImportListsPlexSettingsAuthenticateWithPlex", Type = FieldType.OAuth)]
public string SignIn { get; set; }
public NzbDroneValidationResult Validate()

View File

@@ -2,13 +2,14 @@ using System;
using NLog;
using NzbDrone.Common.Http;
using NzbDrone.Core.Configuration;
using NzbDrone.Core.Localization;
using NzbDrone.Core.Parser;
namespace NzbDrone.Core.ImportLists.Rss.Plex
{
public class PlexRssImport : RssImportBase<PlexRssImportSettings>
{
public override string Name => "Plex Watchlist RSS";
public override string Name => _localizationService.GetLocalizedString("ImportListsPlexSettingsWatchlistRSSName");
public override ImportListType ListType => ImportListType.Plex;
public override TimeSpan MinRefreshInterval => TimeSpan.FromHours(6);
@@ -16,8 +17,9 @@ namespace NzbDrone.Core.ImportLists.Rss.Plex
IImportListStatusService importListStatusService,
IConfigService configService,
IParsingService parsingService,
ILocalizationService localizationService,
Logger logger)
: base(httpClient, importListStatusService, configService, parsingService, logger)
: base(httpClient, importListStatusService, configService, parsingService, localizationService, logger)
{
}

View File

@@ -3,18 +3,19 @@ using System.Xml.Linq;
using NLog;
using NzbDrone.Common.Extensions;
using NzbDrone.Core.Indexers;
using NzbDrone.Core.Indexers.Exceptions;
using NzbDrone.Core.Parser.Model;
namespace NzbDrone.Core.ImportLists.Rss.Plex
{
public class PlexRssImportParser : RssImportBaseParser
{
private readonly Logger _logger;
private static readonly Regex ImdbIdRegex = new (@"(tt\d{7,8})", RegexOptions.IgnoreCase | RegexOptions.Compiled);
public PlexRssImportParser(Logger logger)
: base(logger)
{
_logger = logger;
}
protected override ImportListItemInfo ProcessItem(XElement item)
@@ -53,7 +54,9 @@ namespace NzbDrone.Core.ImportLists.Rss.Plex
if (info.ImdbId.IsNullOrWhiteSpace() && info.TvdbId == 0 && info.TmdbId == 0)
{
throw new UnsupportedFeedException("Each item in the RSS feed must have a guid element with a IMDB ID, TVDB ID or TMDB ID");
_logger.Warn("Each item in the RSS feed must have a guid element with a IMDB ID, TVDB ID or TMDB ID: '{0}'", info.Title);
return null;
}
return info;

View File

@@ -16,7 +16,7 @@ namespace NzbDrone.Core.ImportLists.Rss.Plex
{
private PlexRssImportSettingsValidator Validator => new ();
[FieldDefinition(0, Label = "Url", Type = FieldType.Textbox, HelpLink = "https://app.plex.tv/desktop/#!/settings/watchlist")]
[FieldDefinition(0, Label = "ImportListsSettingsRssUrl", Type = FieldType.Textbox, HelpLink = "https://app.plex.tv/desktop/#!/settings/watchlist")]
public override string Url { get; set; }
public override NzbDroneValidationResult Validate()

View File

@@ -3,6 +3,7 @@ using System.Collections.Generic;
using NLog;
using NzbDrone.Common.Http;
using NzbDrone.Core.Configuration;
using NzbDrone.Core.Localization;
using NzbDrone.Core.Parser;
using NzbDrone.Core.Parser.Model;
@@ -19,8 +20,9 @@ namespace NzbDrone.Core.ImportLists.Rss
IImportListStatusService importListStatusService,
IConfigService configService,
IParsingService parsingService,
ILocalizationService localizationService,
Logger logger)
: base(httpClient, importListStatusService, configService, parsingService, logger)
: base(httpClient, importListStatusService, configService, parsingService, localizationService, logger)
{
}

View File

@@ -18,7 +18,7 @@ namespace NzbDrone.Core.ImportLists.Rss
public string BaseUrl { get; set; }
[FieldDefinition(0, Label = "Url", Type = FieldType.Textbox)]
[FieldDefinition(0, Label = "ImportListsSettingsRssUrl", Type = FieldType.Textbox)]
public virtual string Url { get; set; }
public virtual NzbDroneValidationResult Validate()

View File

@@ -4,6 +4,7 @@ using NLog;
using NzbDrone.Common.Extensions;
using NzbDrone.Common.Http;
using NzbDrone.Core.Configuration;
using NzbDrone.Core.Localization;
using NzbDrone.Core.Parser;
using NzbDrone.Core.Parser.Model;
using NzbDrone.Core.Validation;
@@ -28,8 +29,9 @@ namespace NzbDrone.Core.ImportLists.Simkl
IImportListStatusService importListStatusService,
IConfigService configService,
IParsingService parsingService,
ILocalizationService localizationService,
Logger logger)
: base(httpClient, importListStatusService, configService, parsingService, logger)
: base(httpClient, importListStatusService, configService, parsingService, localizationService, logger)
{
_importListRepository = netImportRepository;
}

View File

@@ -37,19 +37,19 @@ namespace NzbDrone.Core.ImportLists.Simkl
public string BaseUrl { get; set; }
[FieldDefinition(0, Label = "Access Token", Type = FieldType.Textbox, Hidden = HiddenType.Hidden)]
[FieldDefinition(0, Label = "ImportListsSettingsAccessToken", Type = FieldType.Textbox, Hidden = HiddenType.Hidden)]
public string AccessToken { get; set; }
[FieldDefinition(0, Label = "Refresh Token", Type = FieldType.Textbox, Hidden = HiddenType.Hidden)]
[FieldDefinition(0, Label = "ImportListsSettingsRefreshToken", Type = FieldType.Textbox, Hidden = HiddenType.Hidden)]
public string RefreshToken { get; set; }
[FieldDefinition(0, Label = "Expires", Type = FieldType.Textbox, Hidden = HiddenType.Hidden)]
[FieldDefinition(0, Label = "ImportListsSettingsExpires", Type = FieldType.Textbox, Hidden = HiddenType.Hidden)]
public DateTime Expires { get; set; }
[FieldDefinition(0, Label = "Auth User", Type = FieldType.Textbox, Hidden = HiddenType.Hidden)]
[FieldDefinition(0, Label = "ImportListsSettingsAuthUser", Type = FieldType.Textbox, Hidden = HiddenType.Hidden)]
public string AuthUser { get; set; }
[FieldDefinition(99, Label = "Authenticate with Simkl", Type = FieldType.OAuth)]
[FieldDefinition(99, Label = "ImportListsSimklSettingsAuthenticatewithSimkl", Type = FieldType.OAuth)]
public string SignIn { get; set; }
public NzbDroneValidationResult Validate()

View File

@@ -1,6 +1,7 @@
using NLog;
using NzbDrone.Common.Http;
using NzbDrone.Core.Configuration;
using NzbDrone.Core.Localization;
using NzbDrone.Core.Parser;
namespace NzbDrone.Core.ImportLists.Simkl.User
@@ -12,12 +13,13 @@ namespace NzbDrone.Core.ImportLists.Simkl.User
IImportListStatusService netImportStatusService,
IConfigService configService,
IParsingService parsingService,
ILocalizationService localizationService,
Logger logger)
: base(netImportRepository, httpClient, netImportStatusService, configService, parsingService, logger)
: base(netImportRepository, httpClient, netImportStatusService, configService, parsingService, localizationService, logger)
{
}
public override string Name => "Simkl User Watchlist";
public override string Name => _localizationService.GetLocalizedString("ImportListsSimklSettingsName");
public override IImportListRequestGenerator GetRequestGenerator()
{

View File

@@ -1,18 +1,18 @@
using System.Runtime.Serialization;
using NzbDrone.Core.Annotations;
namespace NzbDrone.Core.ImportLists.Simkl.User
{
public enum SimklUserListType
{
[EnumMember(Value = "Watching")]
[FieldOption(Label = "ImportListsSimklSettingsUserListTypeWatching")]
Watching = 0,
[EnumMember(Value = "Plan To Watch")]
[FieldOption(Label = "ImportListsSimklSettingsUserListTypePlanToWatch")]
PlanToWatch = 1,
[EnumMember(Value = "Hold")]
[FieldOption(Label = "ImportListsSimklSettingsUserListTypeHold")]
Hold = 2,
[EnumMember(Value = "Completed")]
[FieldOption(Label = "ImportListsSimklSettingsUserListTypeCompleted")]
Completed = 3,
[EnumMember(Value = "Dropped")]
[FieldOption(Label = "ImportListsSimklSettingsUserListTypeDropped")]
Dropped = 4
}
}

View File

@@ -22,10 +22,10 @@ namespace NzbDrone.Core.ImportLists.Simkl.User
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 = "ImportListsSimklSettingsListType", Type = FieldType.Select, SelectOptions = typeof(SimklUserListType), HelpText = "ImportListsSimklSettingsListTypeHelpText")]
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")]
[FieldDefinition(1, Label = "ImportListsSimklSettingsShowType", Type = FieldType.Select, SelectOptions = typeof(SimklUserShowType), HelpText = "ImportListsSimklSettingsShowTypeHelpText")]
public int ShowType { get; set; }
}
}

View File

@@ -5,6 +5,7 @@ using FluentValidation.Results;
using NLog;
using NzbDrone.Common.Extensions;
using NzbDrone.Core.Configuration;
using NzbDrone.Core.Localization;
using NzbDrone.Core.Parser;
using NzbDrone.Core.Parser.Model;
using NzbDrone.Core.Validation;
@@ -23,8 +24,9 @@ namespace NzbDrone.Core.ImportLists.Sonarr
IImportListStatusService importListStatusService,
IConfigService configService,
IParsingService parsingService,
ILocalizationService localizationService,
Logger logger)
: base(importListStatusService, configService, parsingService, logger)
: base(importListStatusService, configService, parsingService, localizationService, logger)
{
_sonarrV3Proxy = sonarrV3Proxy;
}

View File

@@ -29,22 +29,23 @@ namespace NzbDrone.Core.ImportLists.Sonarr
RootFolderPaths = Array.Empty<string>();
}
[FieldDefinition(0, Label = "Full URL", HelpText = "URL, including port, of the Sonarr instance to import from")]
[FieldDefinition(0, Label = "ImportListsSonarrSettingsFullUrl", HelpText = "ImportListsSonarrSettingsFullUrlHelpText")]
public string BaseUrl { get; set; }
[FieldDefinition(1, Label = "API Key", HelpText = "Apikey of the Sonarr instance to import from")]
[FieldDefinition(1, Label = "ApiKey", HelpText = "ImportListsSonarrSettingsApiKeyHelpText")]
public string ApiKey { get; set; }
[FieldDefinition(2, Type = FieldType.Select, SelectOptionsProviderAction = "getProfiles", Label = "Quality Profiles", HelpText = "Quality Profiles from the source instance to import from")]
[FieldDefinition(2, Type = FieldType.Select, SelectOptionsProviderAction = "getProfiles", Label = "QualityProfiles", HelpText = "ImportListsSonarrSettingsQualityProfilesHelpText")]
public IEnumerable<int> ProfileIds { get; set; }
// TODO: Remove this eventually, no translation added as deprecated
[FieldDefinition(3, Type = FieldType.Select, SelectOptionsProviderAction = "getLanguageProfiles", Label = "Language Profiles", HelpText = "Language Profiles from the source instance to import from")]
public IEnumerable<int> LanguageProfileIds { get; set; }
[FieldDefinition(4, Type = FieldType.Select, SelectOptionsProviderAction = "getTags", Label = "Tags", HelpText = "Tags from the source instance to import from")]
[FieldDefinition(4, Type = FieldType.Select, SelectOptionsProviderAction = "getTags", Label = "Tags", HelpText = "ImportListsSonarrSettingsTagsHelpText")]
public IEnumerable<int> TagIds { get; set; }
[FieldDefinition(5, Type = FieldType.Select, SelectOptionsProviderAction = "getRootFolders", Label = "Root Folders", HelpText = "Root Folders from the source instance to import from")]
[FieldDefinition(5, Type = FieldType.Select, SelectOptionsProviderAction = "getRootFolders", Label = "RootFolders", HelpText = "ImportListsSonarrSettingsRootFoldersHelpText")]
public IEnumerable<string> RootFolderPaths { get; set; }
public NzbDroneValidationResult Validate()

View File

@@ -6,6 +6,7 @@ using Newtonsoft.Json;
using NLog;
using NzbDrone.Common.Extensions;
using NzbDrone.Common.Http;
using NzbDrone.Core.Localization;
namespace NzbDrone.Core.ImportLists.Sonarr
{
@@ -23,10 +24,12 @@ namespace NzbDrone.Core.ImportLists.Sonarr
{
private readonly IHttpClient _httpClient;
private readonly Logger _logger;
private readonly ILocalizationService _localizationService;
public SonarrV3Proxy(IHttpClient httpClient, Logger logger)
public SonarrV3Proxy(IHttpClient httpClient, ILocalizationService localizationService, Logger logger)
{
_httpClient = httpClient;
_localizationService = localizationService;
_logger = logger;
}
@@ -66,22 +69,22 @@ namespace NzbDrone.Core.ImportLists.Sonarr
if (ex.Response.StatusCode == HttpStatusCode.Unauthorized)
{
_logger.Error(ex, "API Key is invalid");
return new ValidationFailure("ApiKey", "API Key is invalid");
return new ValidationFailure("ApiKey", _localizationService.GetLocalizedString("ImportListsValidationInvalidApiKey"));
}
if (ex.Response.HasHttpRedirect)
{
_logger.Error(ex, "Sonarr returned redirect and is invalid");
return new ValidationFailure("BaseUrl", "Sonarr URL is invalid, are you missing a URL base?");
return new ValidationFailure("BaseUrl", _localizationService.GetLocalizedString("ImportListsSonarrValidationInvalidUrl"));
}
_logger.Error(ex, "Unable to connect to import list.");
return new ValidationFailure(string.Empty, $"Unable to connect to import list: {ex.Message}. Check the log surrounding this error for details.");
return new ValidationFailure(string.Empty, _localizationService.GetLocalizedString("ImportListsValidationUnableToConnectException", new Dictionary<string, object> { { "exceptionMessage", ex.Message } }));
}
catch (Exception ex)
{
_logger.Error(ex, "Unable to connect to import list.");
return new ValidationFailure(string.Empty, $"Unable to connect to import list: {ex.Message}. Check the log surrounding this error for details.");
return new ValidationFailure(string.Empty, _localizationService.GetLocalizedString("ImportListsValidationUnableToConnectException", new Dictionary<string, object> { { "exceptionMessage", ex.Message } }));
}
return null;

View File

@@ -1,6 +1,8 @@
using System.Collections.Generic;
using NLog;
using NzbDrone.Common.Http;
using NzbDrone.Core.Configuration;
using NzbDrone.Core.Localization;
using NzbDrone.Core.Parser;
namespace NzbDrone.Core.ImportLists.Trakt.List
@@ -12,12 +14,13 @@ namespace NzbDrone.Core.ImportLists.Trakt.List
IImportListStatusService netImportStatusService,
IConfigService configService,
IParsingService parsingService,
ILocalizationService localizationService,
Logger logger)
: base(netImportRepository, httpClient, netImportStatusService, configService, parsingService, logger)
: base(netImportRepository, httpClient, netImportStatusService, configService, parsingService, localizationService, logger)
{
}
public override string Name => "Trakt List";
public override string Name => _localizationService.GetLocalizedString("TypeOfList", new Dictionary<string, object> { { "typeOfList", "Trakt" } });
public override IImportListRequestGenerator GetRequestGenerator()
{

View File

@@ -17,10 +17,10 @@ namespace NzbDrone.Core.ImportLists.Trakt.List
{
protected override AbstractValidator<TraktListSettings> Validator => new TraktListSettingsValidator();
[FieldDefinition(1, Label = "Username", HelpText = "Username for the List to import from")]
[FieldDefinition(1, Label = "Username", HelpText = "ImportListsTraktSettingsUsernameHelpText")]
public string Username { get; set; }
[FieldDefinition(2, Label = "List Name", HelpText = "List name for import, list must be public or you must have access to the list")]
[FieldDefinition(2, Label = "ImportListsTraktSettingsListName", HelpText = "ImportListsTraktSettingsListNameHelpText")]
public string Listname { get; set; }
}
}

View File

@@ -1,6 +1,7 @@
using NLog;
using NzbDrone.Common.Http;
using NzbDrone.Core.Configuration;
using NzbDrone.Core.Localization;
using NzbDrone.Core.Parser;
namespace NzbDrone.Core.ImportLists.Trakt.Popular
@@ -12,12 +13,13 @@ namespace NzbDrone.Core.ImportLists.Trakt.Popular
IImportListStatusService netImportStatusService,
IConfigService configService,
IParsingService parsingService,
ILocalizationService localizationService,
Logger logger)
: base(netImportRepository, httpClient, netImportStatusService, configService, parsingService, logger)
: base(netImportRepository, httpClient, netImportStatusService, configService, parsingService, localizationService, logger)
{
}
public override string Name => "Trakt Popular List";
public override string Name => _localizationService.GetLocalizedString("ImportListsTraktSettingsPopularName");
public override IParseImportListResponse GetParser()
{

View File

@@ -1,31 +1,30 @@
using System.Runtime.Serialization;
using NzbDrone.Core.Annotations;
namespace NzbDrone.Core.ImportLists.Trakt.Popular
{
public enum TraktPopularListType
{
[EnumMember(Value = "Trending Shows")]
[FieldOption(Label = "ImportListsTraktSettingsPopularListTypeTrendingShows")]
Trending = 0,
[EnumMember(Value = "Popular Shows")]
[FieldOption(Label = "ImportListsTraktSettingsPopularListTypePopularShows")]
Popular = 1,
[EnumMember(Value = "Anticipated Shows")]
[FieldOption(Label = "ImportListsTraktSettingsPopularListTypeAnticipatedShows")]
Anticipated = 2,
[EnumMember(Value = "Top Watched Shows By Week")]
[FieldOption(Label = "ImportListsTraktSettingsPopularListTypeTopWeekShows")]
TopWatchedByWeek = 3,
[EnumMember(Value = "Top Watched Shows By Month")]
[FieldOption(Label = "ImportListsTraktSettingsPopularListTypeTopMonthShows")]
TopWatchedByMonth = 4,
[EnumMember(Value = "Top Watched Shows By Year")]
[FieldOption(Label = "ImportListsTraktSettingsPopularListTypeTopYearShows")]
TopWatchedByYear = 5,
[EnumMember(Value = "Top Watched Shows Of All Time")]
[FieldOption(Label = "ImportListsTraktSettingsPopularListTypeTopAllTimeShows")]
TopWatchedByAllTime = 6,
[EnumMember(Value = "Recommended Shows By Week")]
[FieldOption(Label = "ImportListsTraktSettingsPopularListTypeRecommendedWeekShows")]
RecommendedByWeek = 7,
[EnumMember(Value = "Recommended Shows By Month")]
[FieldOption(Label = "ImportListsTraktSettingsPopularListTypeRecommendedMonthShows")]
RecommendedByMonth = 8,
[EnumMember(Value = "Recommended Shows By Year")]
[FieldOption(Label = "ImportListsTraktSettingsPopularListTypeRecommendedYearShows")]
RecommendedByYear = 9,
[EnumMember(Value = "Recommended Shows Of All Time")]
[FieldOption(Label = "ImportListsTraktSettingsPopularListTypeRecommendedAllTimeShows")]
RecommendedByAllTime = 10
}
}

View File

@@ -35,16 +35,16 @@ namespace NzbDrone.Core.ImportLists.Trakt.Popular
TraktListType = (int)TraktPopularListType.Popular;
}
[FieldDefinition(1, Label = "List Type", Type = FieldType.Select, SelectOptions = typeof(TraktPopularListType), HelpText = "Type of list you're seeking to import from")]
[FieldDefinition(1, Label = "ImportListsTraktSettingsListType", Type = FieldType.Select, SelectOptions = typeof(TraktPopularListType), HelpText = "ImportListsTraktSettingsListTypeHelpText")]
public int TraktListType { get; set; }
[FieldDefinition(2, Label = "Rating", HelpText = "Filter series by rating range (0-100)")]
[FieldDefinition(2, Label = "ImportListsTraktSettingsRating", HelpText = "ImportListsTraktSettingsRatingHelpText")]
public string Rating { get; set; }
[FieldDefinition(4, Label = "Genres", HelpText = "Filter series by Trakt Genre Slug (Comma Separated) Only for Popular Lists")]
[FieldDefinition(4, Label = "ImportListsTraktSettingsGenres", HelpText = "ImportListsTraktSettingsGenresHelpText")]
public string Genres { get; set; }
[FieldDefinition(5, Label = "Years", HelpText = "Filter series by year or year range")]
[FieldDefinition(5, Label = "ImportListsTraktSettingsYears", HelpText = "ImportListsTraktSettingsYearsHelpText")]
public string Years { get; set; }
}
}

View File

@@ -4,6 +4,7 @@ using NLog;
using NzbDrone.Common.Extensions;
using NzbDrone.Common.Http;
using NzbDrone.Core.Configuration;
using NzbDrone.Core.Localization;
using NzbDrone.Core.Parser;
using NzbDrone.Core.Parser.Model;
using NzbDrone.Core.Validation;
@@ -28,8 +29,9 @@ namespace NzbDrone.Core.ImportLists.Trakt
IImportListStatusService importListStatusService,
IConfigService configService,
IParsingService parsingService,
ILocalizationService localizationService,
Logger logger)
: base(httpClient, importListStatusService, configService, parsingService, logger)
: base(httpClient, importListStatusService, configService, parsingService, localizationService, logger)
{
_importListRepository = netImportRepository;
}

View File

@@ -48,25 +48,25 @@ namespace NzbDrone.Core.ImportLists.Trakt
public string BaseUrl { get; set; }
[FieldDefinition(0, Label = "Access Token", Type = FieldType.Textbox, Hidden = HiddenType.Hidden)]
[FieldDefinition(0, Label = "ImportListsSettingsAccessToken", Type = FieldType.Textbox, Hidden = HiddenType.Hidden)]
public string AccessToken { get; set; }
[FieldDefinition(0, Label = "Refresh Token", Type = FieldType.Textbox, Hidden = HiddenType.Hidden)]
[FieldDefinition(0, Label = "ImportListsSettingsRefreshToken", Type = FieldType.Textbox, Hidden = HiddenType.Hidden)]
public string RefreshToken { get; set; }
[FieldDefinition(0, Label = "Expires", Type = FieldType.Textbox, Hidden = HiddenType.Hidden)]
[FieldDefinition(0, Label = "ImportListsSettingsExpires", Type = FieldType.Textbox, Hidden = HiddenType.Hidden)]
public DateTime Expires { get; set; }
[FieldDefinition(0, Label = "Auth User", Type = FieldType.Textbox, Hidden = HiddenType.Hidden)]
[FieldDefinition(0, Label = "ImportListsSettingsAuthUser", Type = FieldType.Textbox, Hidden = HiddenType.Hidden)]
public string AuthUser { get; set; }
[FieldDefinition(5, Label = "Limit", HelpText = "Limit the number of series to get")]
[FieldDefinition(5, Label = "ImportListsTraktSettingsLimit", HelpText = "ImportListsTraktSettingsLimitHelpText")]
public int Limit { get; set; }
[FieldDefinition(6, Label = "Additional Parameters", HelpText = "Additional Trakt API parameters", Advanced = true)]
[FieldDefinition(6, Label = "ImportListsTraktSettingsAdditionalParameters", HelpText = "ImportListsTraktSettingsAdditionalParametersHelpText", Advanced = true)]
public string TraktAdditionalParameters { get; set; }
[FieldDefinition(99, Label = "Authenticate with Trakt", Type = FieldType.OAuth)]
[FieldDefinition(99, Label = "ImportListsTraktSettingsAuthenticateWithTrakt", Type = FieldType.OAuth)]
public string SignIn { get; set; }
public NzbDroneValidationResult Validate()

View File

@@ -1,6 +1,7 @@
using NLog;
using NzbDrone.Common.Http;
using NzbDrone.Core.Configuration;
using NzbDrone.Core.Localization;
using NzbDrone.Core.Parser;
namespace NzbDrone.Core.ImportLists.Trakt.User
@@ -12,12 +13,13 @@ namespace NzbDrone.Core.ImportLists.Trakt.User
IImportListStatusService netImportStatusService,
IConfigService configService,
IParsingService parsingService,
ILocalizationService localizationService,
Logger logger)
: base(netImportRepository, httpClient, netImportStatusService, configService, parsingService, logger)
: base(netImportRepository, httpClient, netImportStatusService, configService, parsingService, localizationService, logger)
{
}
public override string Name => "Trakt User";
public override string Name => _localizationService.GetLocalizedString("ImportListsTraktSettingsUserListName");
public override IParseImportListResponse GetParser()
{

View File

@@ -4,11 +4,11 @@ namespace NzbDrone.Core.ImportLists.Trakt.User
{
public enum TraktUserListType
{
[FieldOption(Label = "User Watch List")]
[FieldOption(Label = "ImportListsTraktSettingsUserListTypeWatch")]
UserWatchList = 0,
[FieldOption(Label = "User Watched List")]
[FieldOption(Label = "ImportListsTraktSettingsUserListTypeWatched")]
UserWatchedList = 1,
[FieldOption(Label = "User Collection List")]
[FieldOption(Label = "ImportListsTraktSettingsUserListTypeCollection")]
UserCollectionList = 2
}
}

View File

@@ -25,16 +25,16 @@ namespace NzbDrone.Core.ImportLists.Trakt.User
TraktWatchSorting = (int)TraktUserWatchSorting.Rank;
}
[FieldDefinition(1, Label = "List Type", Type = FieldType.Select, SelectOptions = typeof(TraktUserListType), HelpText = "Type of list you're seeking to import from")]
[FieldDefinition(1, Label = "ImportListsTraktSettingsListType", Type = FieldType.Select, SelectOptions = typeof(TraktUserListType), HelpText = "ImportListsTraktSettingsListTypeHelpText")]
public int TraktListType { get; set; }
[FieldDefinition(2, Label = "Watched List Filter", Type = FieldType.Select, SelectOptions = typeof(TraktUserWatchedListType), HelpText = "If List Type is Watched. Series do you want to import from")]
[FieldDefinition(2, Label = "ImportListsTraktSettingsWatchedListFilter", Type = FieldType.Select, SelectOptions = typeof(TraktUserWatchedListType), HelpText = "ImportListsTraktSettingsWatchedListFilterHelpText")]
public int TraktWatchedListType { get; set; }
[FieldDefinition(3, Label = "Watch List Sorting", Type = FieldType.Select, SelectOptions = typeof(TraktUserWatchSorting), HelpText = "If List Type is Watch")]
[FieldDefinition(3, Label = "ImportListsTraktSettingsWatchedListSorting", Type = FieldType.Select, SelectOptions = typeof(TraktUserWatchSorting), HelpText = "ImportListsTraktSettingsWatchedListSortingHelpText")]
public int TraktWatchSorting { get; set; }
[FieldDefinition(4, Label = "Username", HelpText = "Username for the List to import from (empty to use Auth User)")]
[FieldDefinition(4, Label = "Username", HelpText = "ImportListsTraktSettingsUserListUsernameHelpText")]
public string Username { get; set; }
}

Some files were not shown because too many files have changed in this diff Show More