mirror of
https://github.com/Radarr/Radarr.git
synced 2026-03-12 15:30:39 -04:00
Compare commits
16 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
17c6d11a47 | ||
|
|
a994502e59 | ||
|
|
4154414adf | ||
|
|
c5b12d074e | ||
|
|
578aa14770 | ||
|
|
da1bc0aa88 | ||
|
|
a56d827744 | ||
|
|
a53234a107 | ||
|
|
a015fa3255 | ||
|
|
b2cb95829c | ||
|
|
64fd60a7d5 | ||
|
|
c3368d9e6c | ||
|
|
583c5d501c | ||
|
|
af6b16ec57 | ||
|
|
7ac5a5843b | ||
|
|
2465815890 |
@@ -19,10 +19,10 @@ indent_size = 4
|
||||
dotnet_sort_system_directives_first = true
|
||||
|
||||
# Avoid "this." and "Me." if not necessary
|
||||
dotnet_style_qualification_for_field = false:refactoring
|
||||
dotnet_style_qualification_for_property = false:refactoring
|
||||
dotnet_style_qualification_for_method = false:refactoring
|
||||
dotnet_style_qualification_for_event = false:refactoring
|
||||
dotnet_style_qualification_for_field = false:warning
|
||||
dotnet_style_qualification_for_property = false:warning
|
||||
dotnet_style_qualification_for_method = false:warning
|
||||
dotnet_style_qualification_for_event = false:warning
|
||||
|
||||
# Indentation preferences
|
||||
csharp_indent_block_contents = true
|
||||
@@ -32,10 +32,6 @@ csharp_indent_case_contents_when_block = true
|
||||
csharp_indent_switch_labels = true
|
||||
csharp_indent_labels = flush_left
|
||||
|
||||
dotnet_style_qualification_for_field = false:suggestion
|
||||
dotnet_style_qualification_for_property = false:suggestion
|
||||
dotnet_style_qualification_for_method = false:suggestion
|
||||
dotnet_style_qualification_for_event = false:suggestion
|
||||
dotnet_naming_style.instance_field_style.capitalization = camel_case
|
||||
dotnet_naming_style.instance_field_style.required_prefix = _
|
||||
|
||||
@@ -68,7 +64,6 @@ dotnet_diagnostic.SA1406.severity = suggestion
|
||||
dotnet_diagnostic.SA1410.severity = suggestion
|
||||
dotnet_diagnostic.SA1411.severity = suggestion
|
||||
dotnet_diagnostic.SA1413.severity = none
|
||||
dotnet_diagnostic.SA1512.severity = none
|
||||
dotnet_diagnostic.SA1516.severity = none
|
||||
dotnet_diagnostic.SA1600.severity = none
|
||||
dotnet_diagnostic.SA1601.severity = none
|
||||
@@ -167,7 +162,6 @@ dotnet_diagnostic.CA1309.severity = suggestion
|
||||
dotnet_diagnostic.CA1310.severity = suggestion
|
||||
dotnet_diagnostic.CA1401.severity = suggestion
|
||||
dotnet_diagnostic.CA1416.severity = suggestion
|
||||
dotnet_diagnostic.CA1419.severity = suggestion
|
||||
dotnet_diagnostic.CA1507.severity = suggestion
|
||||
dotnet_diagnostic.CA1508.severity = suggestion
|
||||
dotnet_diagnostic.CA1707.severity = suggestion
|
||||
@@ -183,6 +177,9 @@ dotnet_diagnostic.CA1720.severity = suggestion
|
||||
dotnet_diagnostic.CA1721.severity = suggestion
|
||||
dotnet_diagnostic.CA1724.severity = suggestion
|
||||
dotnet_diagnostic.CA1725.severity = suggestion
|
||||
dotnet_diagnostic.CA1801.severity = suggestion
|
||||
dotnet_diagnostic.CA1802.severity = suggestion
|
||||
dotnet_diagnostic.CA1805.severity = suggestion
|
||||
dotnet_diagnostic.CA1806.severity = suggestion
|
||||
dotnet_diagnostic.CA1810.severity = suggestion
|
||||
dotnet_diagnostic.CA1812.severity = suggestion
|
||||
@@ -194,11 +191,13 @@ dotnet_diagnostic.CA1819.severity = suggestion
|
||||
dotnet_diagnostic.CA1822.severity = suggestion
|
||||
dotnet_diagnostic.CA1823.severity = suggestion
|
||||
dotnet_diagnostic.CA1824.severity = suggestion
|
||||
dotnet_diagnostic.CA1848.severity = suggestion
|
||||
dotnet_diagnostic.CA2000.severity = suggestion
|
||||
dotnet_diagnostic.CA2002.severity = suggestion
|
||||
dotnet_diagnostic.CA2007.severity = suggestion
|
||||
dotnet_diagnostic.CA2008.severity = suggestion
|
||||
dotnet_diagnostic.CA2009.severity = suggestion
|
||||
dotnet_diagnostic.CA2010.severity = suggestion
|
||||
dotnet_diagnostic.CA2011.severity = suggestion
|
||||
dotnet_diagnostic.CA2012.severity = suggestion
|
||||
dotnet_diagnostic.CA2013.severity = suggestion
|
||||
dotnet_diagnostic.CA2100.severity = suggestion
|
||||
@@ -229,9 +228,6 @@ dotnet_diagnostic.CA2243.severity = suggestion
|
||||
dotnet_diagnostic.CA2244.severity = suggestion
|
||||
dotnet_diagnostic.CA2245.severity = suggestion
|
||||
dotnet_diagnostic.CA2246.severity = suggestion
|
||||
dotnet_diagnostic.CA2249.severity = suggestion
|
||||
dotnet_diagnostic.CA2251.severity = suggestion
|
||||
dotnet_diagnostic.CA2254.severity = suggestion
|
||||
dotnet_diagnostic.CA3061.severity = suggestion
|
||||
dotnet_diagnostic.CA3075.severity = suggestion
|
||||
dotnet_diagnostic.CA3076.severity = suggestion
|
||||
@@ -259,7 +255,7 @@ dotnet_diagnostic.CA5392.severity = suggestion
|
||||
dotnet_diagnostic.CA5394.severity = suggestion
|
||||
dotnet_diagnostic.CA5397.severity = suggestion
|
||||
|
||||
dotnet_diagnostic.SYSLIB0006.severity = none
|
||||
|
||||
|
||||
[*.{js,html,js,hbs,less,css}]
|
||||
charset = utf-8
|
||||
|
||||
9
.esprintrc
Normal file
9
.esprintrc
Normal file
@@ -0,0 +1,9 @@
|
||||
{
|
||||
"paths": [
|
||||
"frontend/src/**/*.js"
|
||||
],
|
||||
"ignored": [
|
||||
"**/node_modules/**/*"
|
||||
],
|
||||
"port": 5004
|
||||
}
|
||||
45
.github/workflows/azuresync.yml
vendored
Normal file
45
.github/workflows/azuresync.yml
vendored
Normal file
@@ -0,0 +1,45 @@
|
||||
name: Sync issue to Azure DevOps work item
|
||||
|
||||
on:
|
||||
issues:
|
||||
types:
|
||||
[opened, edited, deleted, closed, reopened, labeled, unlabeled, assigned]
|
||||
|
||||
concurrency: azuresync-${{ github.event.issue.number }}
|
||||
|
||||
permissions: {}
|
||||
jobs:
|
||||
alert:
|
||||
permissions:
|
||||
issues: write # to update issue body
|
||||
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: danhellem/github-actions-issue-to-work-item@master
|
||||
if: "${{ contains(github.event.issue.labels.*.name, 'Type: Bug') == true }}"
|
||||
env:
|
||||
ado_token: "${{ secrets.ADO_PERSONAL_ACCESS_TOKEN }}"
|
||||
github_token: "${{ github.token }}"
|
||||
ado_organization: "Servarr"
|
||||
ado_project: "Servarr"
|
||||
ado_area_path: "Servarr\\Radarr"
|
||||
ado_wit: "Bug"
|
||||
ado_new_state: "New"
|
||||
ado_active_state: "Active"
|
||||
ado_close_state: "Closed"
|
||||
ado_bypassrules: true
|
||||
log_level: 100
|
||||
- uses: danhellem/github-actions-issue-to-work-item@master
|
||||
if: "${{ contains(github.event.issue.labels.*.name, 'Type: Bug') == false }}"
|
||||
env:
|
||||
ado_token: "${{ secrets.ADO_PERSONAL_ACCESS_TOKEN }}"
|
||||
github_token: "${{ github.token }}"
|
||||
ado_organization: "Servarr"
|
||||
ado_project: "Servarr"
|
||||
ado_area_path: "Servarr\\Radarr"
|
||||
ado_wit: "User Story"
|
||||
ado_new_state: "New"
|
||||
ado_active_state: "Active"
|
||||
ado_close_state: "Closed"
|
||||
ado_bypassrules: true
|
||||
log_level: 100
|
||||
23
.gitignore
vendored
23
.gitignore
vendored
@@ -166,8 +166,27 @@ packages.config.md5sum
|
||||
|
||||
# Common IntelliJ Platform excludes
|
||||
|
||||
# Ignore Rider projects completely for now
|
||||
.idea/
|
||||
# User specific
|
||||
**/.idea/**/workspace.xml
|
||||
**/.idea/**/tasks.xml
|
||||
**/.idea/shelf/*
|
||||
**/.idea/dictionaries
|
||||
**/.idea/.idea.Radarr.Posix
|
||||
**/.idea/.idea.Radarr.Windows
|
||||
|
||||
# Sensitive or high-churn files
|
||||
**/.idea/**/dataSources/
|
||||
**/.idea/**/dataSources.ids
|
||||
**/.idea/**/dataSources.xml
|
||||
**/.idea/**/dataSources.local.xml
|
||||
**/.idea/**/sqlDataSources.xml
|
||||
**/.idea/**/dynamic.xml
|
||||
|
||||
# Rider
|
||||
# Rider auto-generates .iml files, and contentModel.xml
|
||||
**/.idea/**/*.iml
|
||||
**/.idea/**/contentModel.xml
|
||||
**/.idea/**/modules.xml
|
||||
|
||||
# ignore node_modules symlink
|
||||
node_modules
|
||||
|
||||
@@ -76,15 +76,6 @@ Thank you to [<img src="/Logo/jetbrains.svg" alt="JetBrains" width="32"> JetBrai
|
||||
* [<img src="/Logo/rider.svg" alt="Rider" width="32"> Rider](http://www.jetbrains.com/rider/)
|
||||
* [<img src="/Logo/dottrace.svg" alt="dotTrace" width="32"> dotTrace](http://www.jetbrains.com/dottrace/)
|
||||
|
||||
## DigitalOcean
|
||||
|
||||
This project is also supported by DigitalOcean
|
||||
<p>
|
||||
<a href="https://www.digitalocean.com/">
|
||||
<img src="https://opensource.nyc3.cdn.digitaloceanspaces.com/attribution/assets/SVG/DO_Logo_horizontal_blue.svg" width="201px">
|
||||
</a>
|
||||
</p>
|
||||
|
||||
### License
|
||||
|
||||
* [GNU GPL v3](http://www.gnu.org/licenses/gpl.html)
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
// eslint-disable-next-line filenames/match-exported
|
||||
const loaderUtils = require('loader-utils');
|
||||
|
||||
module.exports = function cssVariablesLoader(source) {
|
||||
|
||||
@@ -56,7 +56,6 @@ class HistoryRow extends Component {
|
||||
movie,
|
||||
quality,
|
||||
customFormats,
|
||||
customFormatScore,
|
||||
languages,
|
||||
qualityCutoffNotMet,
|
||||
eventType,
|
||||
@@ -176,7 +175,7 @@ class HistoryRow extends Component {
|
||||
key={name}
|
||||
className={styles.customFormatScore}
|
||||
>
|
||||
{formatCustomFormatScore(customFormatScore)}
|
||||
{formatCustomFormatScore(data.customFormatScore)}
|
||||
</TableRowCell>
|
||||
);
|
||||
}
|
||||
@@ -242,9 +241,8 @@ HistoryRow.propTypes = {
|
||||
movie: PropTypes.object.isRequired,
|
||||
languages: PropTypes.arrayOf(PropTypes.object).isRequired,
|
||||
quality: PropTypes.object.isRequired,
|
||||
customFormats: PropTypes.arrayOf(PropTypes.object),
|
||||
customFormatScore: PropTypes.number.isRequired,
|
||||
qualityCutoffNotMet: PropTypes.bool.isRequired,
|
||||
customFormats: PropTypes.arrayOf(PropTypes.object).isRequired,
|
||||
eventType: PropTypes.string.isRequired,
|
||||
sourceTitle: PropTypes.string.isRequired,
|
||||
date: PropTypes.string.isRequired,
|
||||
|
||||
@@ -75,23 +75,13 @@ class Queue extends Component {
|
||||
return;
|
||||
}
|
||||
|
||||
const nextState = {};
|
||||
|
||||
if (prevProps.items !== items) {
|
||||
nextState.items = items;
|
||||
}
|
||||
|
||||
const selectedIds = this.getSelectedIds();
|
||||
const isPendingSelected = _.some(this.props.items, (item) => {
|
||||
return selectedIds.indexOf(item.id) > -1 && item.status === 'delay';
|
||||
});
|
||||
|
||||
if (isPendingSelected !== this.state.isPendingSelected) {
|
||||
nextState.isPendingSelected = isPendingSelected;
|
||||
}
|
||||
|
||||
if (!_.isEmpty(nextState)) {
|
||||
this.setState(nextState);
|
||||
this.setState({ isPendingSelected });
|
||||
}
|
||||
}
|
||||
|
||||
@@ -224,29 +214,26 @@ class Queue extends Component {
|
||||
|
||||
<PageContentBody>
|
||||
{
|
||||
isRefreshing && !isAllPopulated ?
|
||||
<LoadingIndicator /> :
|
||||
null
|
||||
isRefreshing && !isAllPopulated &&
|
||||
<LoadingIndicator />
|
||||
}
|
||||
|
||||
{
|
||||
!isRefreshing && hasError ?
|
||||
!isRefreshing && hasError &&
|
||||
<div>
|
||||
{translate('FailedToLoadQueue')}
|
||||
</div> :
|
||||
null
|
||||
</div>
|
||||
}
|
||||
|
||||
{
|
||||
isAllPopulated && !hasError && !items.length ?
|
||||
isAllPopulated && !hasError && !items.length &&
|
||||
<div>
|
||||
{translate('QueueIsEmpty')}
|
||||
</div> :
|
||||
null
|
||||
</div>
|
||||
}
|
||||
|
||||
{
|
||||
isAllPopulated && !hasError && !!items.length ?
|
||||
isAllPopulated && !hasError && !!items.length &&
|
||||
<div>
|
||||
<Table
|
||||
columns={columns}
|
||||
@@ -281,8 +268,7 @@ class Queue extends Component {
|
||||
isFetching={isRefreshing}
|
||||
{...otherProps}
|
||||
/>
|
||||
</div> :
|
||||
null
|
||||
</div>
|
||||
}
|
||||
</PageContentBody>
|
||||
|
||||
|
||||
@@ -128,7 +128,6 @@ class QueueRow extends Component {
|
||||
|
||||
{
|
||||
columns.map((column) => {
|
||||
|
||||
const {
|
||||
name,
|
||||
isVisible
|
||||
@@ -235,16 +234,6 @@ class QueueRow extends Component {
|
||||
);
|
||||
}
|
||||
|
||||
if (name === 'year') {
|
||||
return (
|
||||
<TableRowCell key={name}>
|
||||
{
|
||||
movie ? movie.year : ''
|
||||
}
|
||||
</TableRowCell>
|
||||
);
|
||||
}
|
||||
|
||||
if (name === 'title') {
|
||||
return (
|
||||
<TableRowCell key={name}>
|
||||
@@ -373,7 +362,6 @@ QueueRow.propTypes = {
|
||||
estimatedCompletionTime: PropTypes.string,
|
||||
timeleft: PropTypes.string,
|
||||
size: PropTypes.number,
|
||||
year: PropTypes.number,
|
||||
sizeleft: PropTypes.number,
|
||||
showRelativeDates: PropTypes.bool.isRequired,
|
||||
shortDateFormat: PropTypes.string.isRequired,
|
||||
|
||||
@@ -225,19 +225,13 @@ class ImportMovieFooter extends Component {
|
||||
body={
|
||||
<ul>
|
||||
{
|
||||
Array.isArray(importError.responseJSON) ?
|
||||
importError.responseJSON.map((error, index) => {
|
||||
return (
|
||||
<li key={index}>
|
||||
{error.errorMessage}
|
||||
</li>
|
||||
);
|
||||
}) :
|
||||
<li>
|
||||
{
|
||||
JSON.stringify(importError.responseJSON)
|
||||
}
|
||||
</li>
|
||||
importError.responseJSON.map((error, index) => {
|
||||
return (
|
||||
<li key={index}>
|
||||
{error.errorMessage}
|
||||
</li>
|
||||
);
|
||||
})
|
||||
}
|
||||
</ul>
|
||||
}
|
||||
|
||||
@@ -152,19 +152,13 @@ class ImportMovieSelectFolder extends Component {
|
||||
|
||||
<ul>
|
||||
{
|
||||
Array.isArray(saveError.responseJSON) ?
|
||||
saveError.responseJSON.map((e, index) => {
|
||||
return (
|
||||
<li key={index}>
|
||||
{e.errorMessage}
|
||||
</li>
|
||||
);
|
||||
}) :
|
||||
<li>
|
||||
{
|
||||
JSON.stringify(saveError.responseJSON)
|
||||
}
|
||||
</li>
|
||||
saveError.responseJSON.map((e, index) => {
|
||||
return (
|
||||
<li key={index}>
|
||||
{e.errorMessage}
|
||||
</li>
|
||||
);
|
||||
})
|
||||
}
|
||||
</ul>
|
||||
</Alert> :
|
||||
|
||||
@@ -177,7 +177,7 @@ class CalendarOptionsModalContent extends Component {
|
||||
values={weekColumnOptions}
|
||||
value={calendarWeekColumnHeader}
|
||||
onChange={this.onGlobalInputChange}
|
||||
helpText={translate('SettingsWeekColumnHeaderHelpText')}
|
||||
helpText={translate('HelpText')}
|
||||
/>
|
||||
</FormGroup>
|
||||
|
||||
|
||||
@@ -113,12 +113,10 @@ class EnhancedSelectInput extends Component {
|
||||
this._scheduleUpdate();
|
||||
}
|
||||
|
||||
if (!Array.isArray(this.props.value)) {
|
||||
if (prevProps.value !== this.props.value || prevProps.values !== this.props.values) {
|
||||
this.setState({
|
||||
selectedIndex: getSelectedIndex(this.props)
|
||||
});
|
||||
}
|
||||
if (!Array.isArray(this.props.value) && prevProps.value !== this.props.value) {
|
||||
this.setState({
|
||||
selectedIndex: getSelectedIndex(this.props)
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -334,11 +332,6 @@ class EnhancedSelectInput extends Component {
|
||||
|
||||
const isMultiSelect = Array.isArray(value);
|
||||
const selectedOption = getSelectedOption(selectedIndex, values);
|
||||
let selectedValue = value;
|
||||
|
||||
if (!values.length) {
|
||||
selectedValue = isMultiSelect ? [] : '';
|
||||
}
|
||||
|
||||
return (
|
||||
<div>
|
||||
@@ -379,17 +372,15 @@ class EnhancedSelectInput extends Component {
|
||||
onPress={this.onPress}
|
||||
>
|
||||
{
|
||||
isFetching ?
|
||||
isFetching &&
|
||||
<LoadingIndicator
|
||||
className={styles.loading}
|
||||
size={20}
|
||||
/> :
|
||||
null
|
||||
/>
|
||||
}
|
||||
|
||||
{
|
||||
isFetching ?
|
||||
null :
|
||||
!isFetching &&
|
||||
<Icon
|
||||
name={icons.CARET_DOWN}
|
||||
/>
|
||||
@@ -409,7 +400,7 @@ class EnhancedSelectInput extends Component {
|
||||
onPress={this.onPress}
|
||||
>
|
||||
<SelectedValueComponent
|
||||
value={selectedValue}
|
||||
value={value}
|
||||
values={values}
|
||||
{...selectedValueOptions}
|
||||
{...selectedOption}
|
||||
@@ -427,17 +418,15 @@ class EnhancedSelectInput extends Component {
|
||||
>
|
||||
|
||||
{
|
||||
isFetching ?
|
||||
isFetching &&
|
||||
<LoadingIndicator
|
||||
className={styles.loading}
|
||||
size={20}
|
||||
/> :
|
||||
null
|
||||
/>
|
||||
}
|
||||
|
||||
{
|
||||
isFetching ?
|
||||
null :
|
||||
!isFetching &&
|
||||
<Icon
|
||||
name={icons.CARET_DOWN}
|
||||
/>
|
||||
@@ -517,7 +506,7 @@ class EnhancedSelectInput extends Component {
|
||||
</Manager>
|
||||
|
||||
{
|
||||
isMobile ?
|
||||
isMobile &&
|
||||
<Modal
|
||||
className={styles.optionsModal}
|
||||
size={sizes.EXTRA_SMALL}
|
||||
@@ -568,8 +557,7 @@ class EnhancedSelectInput extends Component {
|
||||
}
|
||||
</Scroller>
|
||||
</ModalBody>
|
||||
</Modal> :
|
||||
null
|
||||
</Modal>
|
||||
}
|
||||
</div>
|
||||
);
|
||||
|
||||
@@ -24,7 +24,7 @@ function HintedSelectInputSelectedValue(props) {
|
||||
>
|
||||
<div className={styles.valueText}>
|
||||
{
|
||||
isMultiSelect ?
|
||||
isMultiSelect &&
|
||||
value.map((key, index) => {
|
||||
const v = valuesMap[key];
|
||||
return (
|
||||
@@ -32,28 +32,26 @@ function HintedSelectInputSelectedValue(props) {
|
||||
{v ? v.value : key}
|
||||
</Label>
|
||||
);
|
||||
}) :
|
||||
null
|
||||
})
|
||||
}
|
||||
|
||||
{
|
||||
isMultiSelect ? null : value
|
||||
!isMultiSelect && value
|
||||
}
|
||||
</div>
|
||||
|
||||
{
|
||||
hint != null && includeHint ?
|
||||
hint != null && includeHint &&
|
||||
<div className={styles.hintText}>
|
||||
{hint}
|
||||
</div> :
|
||||
null
|
||||
</div>
|
||||
}
|
||||
</EnhancedSelectInputSelectedValue>
|
||||
);
|
||||
}
|
||||
|
||||
HintedSelectInputSelectedValue.propTypes = {
|
||||
value: PropTypes.oneOfType([PropTypes.number, PropTypes.string, PropTypes.arrayOf(PropTypes.oneOfType([PropTypes.string, PropTypes.number]))]).isRequired,
|
||||
value: PropTypes.oneOfType([PropTypes.string, PropTypes.arrayOf(PropTypes.oneOfType([PropTypes.string, PropTypes.number]))]).isRequired,
|
||||
values: PropTypes.arrayOf(PropTypes.object).isRequired,
|
||||
hint: PropTypes.string,
|
||||
isMultiSelect: PropTypes.bool.isRequired,
|
||||
|
||||
@@ -68,7 +68,7 @@ RootFolderSelectInputOption.propTypes = {
|
||||
value: PropTypes.string.isRequired,
|
||||
freeSpace: PropTypes.number,
|
||||
movieFolder: PropTypes.string,
|
||||
isMissing: PropTypes.bool,
|
||||
isMissing: PropTypes.boolean,
|
||||
isMobile: PropTypes.bool.isRequired,
|
||||
isWindows: PropTypes.bool
|
||||
};
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
/* eslint-disable no-bitwise */
|
||||
import PropTypes from 'prop-types';
|
||||
import React, { Component } from 'react';
|
||||
import translate from 'Utilities/String/translate';
|
||||
import EnhancedSelectInput from './EnhancedSelectInput';
|
||||
import styles from './UMaskInput.css';
|
||||
|
||||
@@ -102,16 +101,16 @@ class UMaskInput extends Component {
|
||||
</div>
|
||||
<div className={styles.details}>
|
||||
<div>
|
||||
<label>{translate('UMask')}</label>
|
||||
<label>UMask</label>
|
||||
<div className={styles.value}>{umask}</div>
|
||||
</div>
|
||||
<div>
|
||||
<label>{translate('Folder')}</label>
|
||||
<label>Folder</label>
|
||||
<div className={styles.value}>{folder}</div>
|
||||
<div className={styles.unit}>d{formatPermissions(folderNum)}</div>
|
||||
</div>
|
||||
<div>
|
||||
<label>{translate('File')}</label>
|
||||
<label>File</label>
|
||||
<div className={styles.value}>{file}</div>
|
||||
<div className={styles.unit}>{formatPermissions(fileNum)}</div>
|
||||
</div>
|
||||
|
||||
@@ -60,7 +60,7 @@ class FilterMenu extends Component {
|
||||
iconName={icons.FILTER}
|
||||
text={translate('Filter')}
|
||||
isDisabled={isDisabled}
|
||||
showIndicator={selectedFilterKey !== 'all'}
|
||||
indicator={selectedFilterKey !== 'all'}
|
||||
/>
|
||||
|
||||
<FilterMenuContent
|
||||
|
||||
@@ -1,19 +1,11 @@
|
||||
.menuButton {
|
||||
composes: menuButton from '~./MenuButton.css';
|
||||
|
||||
position: relative;
|
||||
|
||||
&:hover {
|
||||
color: #666;
|
||||
}
|
||||
}
|
||||
|
||||
.indicatorContainer {
|
||||
position: absolute;
|
||||
top: 10px;
|
||||
left: 10px;
|
||||
}
|
||||
|
||||
.label {
|
||||
margin-left: 5px;
|
||||
}
|
||||
|
||||
@@ -1,15 +1,13 @@
|
||||
import classNames from 'classnames';
|
||||
import PropTypes from 'prop-types';
|
||||
import React from 'react';
|
||||
import Icon from 'Components/Icon';
|
||||
import MenuButton from 'Components/Menu/MenuButton';
|
||||
import { icons } from 'Helpers/Props';
|
||||
import styles from './PageMenuButton.css';
|
||||
|
||||
function PageMenuButton(props) {
|
||||
const {
|
||||
iconName,
|
||||
showIndicator,
|
||||
indicator,
|
||||
text,
|
||||
...otherProps
|
||||
} = props;
|
||||
@@ -24,22 +22,6 @@ function PageMenuButton(props) {
|
||||
size={18}
|
||||
/>
|
||||
|
||||
{
|
||||
showIndicator ?
|
||||
<span
|
||||
className={classNames(
|
||||
styles.indicatorContainer,
|
||||
'fa-layers fa-fw'
|
||||
)}
|
||||
>
|
||||
<Icon
|
||||
name={icons.CIRCLE}
|
||||
size={9}
|
||||
/>
|
||||
</span> :
|
||||
null
|
||||
}
|
||||
|
||||
<div className={styles.label}>
|
||||
{text}
|
||||
</div>
|
||||
@@ -50,11 +32,11 @@ function PageMenuButton(props) {
|
||||
PageMenuButton.propTypes = {
|
||||
iconName: PropTypes.object.isRequired,
|
||||
text: PropTypes.string,
|
||||
showIndicator: PropTypes.bool.isRequired
|
||||
indicator: PropTypes.bool.isRequired
|
||||
};
|
||||
|
||||
PageMenuButton.defaultProps = {
|
||||
showIndicator: false
|
||||
indicator: false
|
||||
};
|
||||
|
||||
export default PageMenuButton;
|
||||
|
||||
@@ -9,7 +9,7 @@ import styles from './ToolbarMenuButton.css';
|
||||
function ToolbarMenuButton(props) {
|
||||
const {
|
||||
iconName,
|
||||
showIndicator,
|
||||
indicator,
|
||||
text,
|
||||
...otherProps
|
||||
} = props;
|
||||
@@ -26,7 +26,7 @@ function ToolbarMenuButton(props) {
|
||||
/>
|
||||
|
||||
{
|
||||
showIndicator &&
|
||||
indicator &&
|
||||
<span
|
||||
className={classNames(
|
||||
styles.indicatorContainer,
|
||||
@@ -53,11 +53,11 @@ function ToolbarMenuButton(props) {
|
||||
ToolbarMenuButton.propTypes = {
|
||||
iconName: PropTypes.object.isRequired,
|
||||
text: PropTypes.string,
|
||||
showIndicator: PropTypes.bool.isRequired
|
||||
indicator: PropTypes.bool.isRequired
|
||||
};
|
||||
|
||||
ToolbarMenuButton.defaultProps = {
|
||||
showIndicator: false
|
||||
indicator: false
|
||||
};
|
||||
|
||||
export default ToolbarMenuButton;
|
||||
|
||||
@@ -19,7 +19,7 @@
|
||||
}
|
||||
}
|
||||
|
||||
@media only screen and (max-width: $breakpointExtraLarge) {
|
||||
@media only screen and (max-width: $breakpointLarge) {
|
||||
.contentFooter {
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
|
||||
@@ -20,11 +20,7 @@
|
||||
|
||||
.frontTextContainer {
|
||||
z-index: 1;
|
||||
color: var(--progressBarFrontTextColor);
|
||||
}
|
||||
|
||||
.backTextContainer {
|
||||
color: var(--progressBarBackTextColor);
|
||||
color: var(--white);
|
||||
}
|
||||
|
||||
.backTextContainer,
|
||||
|
||||
@@ -73,7 +73,7 @@ function getInfoRowProps(row, props) {
|
||||
return {
|
||||
title: translate('Ratings'),
|
||||
iconName: icons.HEART,
|
||||
label: `${(props.ratings.tmdb.value * 10).toFixed()}%`
|
||||
label: `${props.ratings.tmdb.value * 10}%`
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -47,10 +47,6 @@ export const possibleFilterTypes = {
|
||||
{ key: filterTypes.CONTAINS, value: 'contains' },
|
||||
{ key: filterTypes.NOT_CONTAINS, value: 'does not contain' },
|
||||
{ key: filterTypes.EQUAL, value: 'equal' },
|
||||
{ key: filterTypes.NOT_EQUAL, value: 'not equal' },
|
||||
{ key: filterTypes.STARTS_WITH, value: 'starts with' },
|
||||
{ key: filterTypes.NOT_STARTS_WITH, value: 'does not start with' },
|
||||
{ key: filterTypes.ENDS_WITH, value: 'ends with' },
|
||||
{ key: filterTypes.NOT_ENDS_WITH, value: 'does not end with' }
|
||||
{ key: filterTypes.NOT_EQUAL, value: 'not equal' }
|
||||
]
|
||||
};
|
||||
|
||||
@@ -39,22 +39,6 @@ const filterTypePredicates = {
|
||||
|
||||
[filterTypes.NOT_EQUAL]: function(itemValue, filterValue) {
|
||||
return itemValue !== filterValue;
|
||||
},
|
||||
|
||||
[filterTypes.STARTS_WITH]: function(itemValue, filterValue) {
|
||||
return itemValue.toLowerCase().startsWith(filterValue.toLowerCase());
|
||||
},
|
||||
|
||||
[filterTypes.NOT_STARTS_WITH]: function(itemValue, filterValue) {
|
||||
return !itemValue.toLowerCase().startsWith(filterValue.toLowerCase());
|
||||
},
|
||||
|
||||
[filterTypes.ENDS_WITH]: function(itemValue, filterValue) {
|
||||
return itemValue.toLowerCase().endsWith(filterValue.toLowerCase());
|
||||
},
|
||||
|
||||
[filterTypes.NOT_ENDS_WITH]: function(itemValue, filterValue) {
|
||||
return !itemValue.toLowerCase().endsWith(filterValue.toLowerCase());
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -10,10 +10,6 @@ export const LESS_THAN = 'lessThan';
|
||||
export const LESS_THAN_OR_EQUAL = 'lessThanOrEqual';
|
||||
export const NOT_CONTAINS = 'notContains';
|
||||
export const NOT_EQUAL = 'notEqual';
|
||||
export const STARTS_WITH = 'startsWith';
|
||||
export const NOT_STARTS_WITH = 'notStartsWith';
|
||||
export const ENDS_WITH = 'endsWith';
|
||||
export const NOT_ENDS_WITH = 'notEndsWith';
|
||||
|
||||
export const all = [
|
||||
CONTAINS,
|
||||
@@ -27,9 +23,5 @@ export const all = [
|
||||
IN_LAST,
|
||||
NOT_IN_LAST,
|
||||
IN_NEXT,
|
||||
NOT_IN_NEXT,
|
||||
STARTS_WITH,
|
||||
NOT_STARTS_WITH,
|
||||
ENDS_WITH,
|
||||
NOT_ENDS_WITH
|
||||
NOT_IN_NEXT
|
||||
];
|
||||
|
||||
@@ -64,15 +64,6 @@ const columns = [
|
||||
isSortable: true,
|
||||
isVisible: true
|
||||
},
|
||||
{
|
||||
name: 'customFormats',
|
||||
label: React.createElement(Icon, {
|
||||
name: icons.INTERACTIVE,
|
||||
title: translate('CustomFormat')
|
||||
}),
|
||||
isSortable: true,
|
||||
isVisible: true
|
||||
},
|
||||
{
|
||||
name: 'rejections',
|
||||
label: React.createElement(Icon, {
|
||||
|
||||
@@ -5,10 +5,8 @@
|
||||
}
|
||||
|
||||
.quality,
|
||||
.languages {
|
||||
.language {
|
||||
composes: cell from '~Components/Table/Cells/TableRowCell.css';
|
||||
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.label {
|
||||
@@ -23,7 +21,3 @@
|
||||
margin-top: 0;
|
||||
text-align: start;
|
||||
}
|
||||
|
||||
.customFormatTooltip {
|
||||
max-width: 250px;
|
||||
}
|
||||
|
||||
@@ -12,7 +12,6 @@ import SelectLanguageModal from 'InteractiveImport/Language/SelectLanguageModal'
|
||||
import SelectMovieModal from 'InteractiveImport/Movie/SelectMovieModal';
|
||||
import SelectQualityModal from 'InteractiveImport/Quality/SelectQualityModal';
|
||||
import SelectReleaseGroupModal from 'InteractiveImport/ReleaseGroup/SelectReleaseGroupModal';
|
||||
import MovieFormats from 'Movie/MovieFormats';
|
||||
import MovieLanguage from 'Movie/MovieLanguage';
|
||||
import MovieQuality from 'Movie/MovieQuality';
|
||||
import formatBytes from 'Utilities/Number/formatBytes';
|
||||
@@ -151,7 +150,6 @@ class InteractiveImportRow extends Component {
|
||||
languages,
|
||||
releaseGroup,
|
||||
size,
|
||||
customFormats,
|
||||
rejections,
|
||||
isReprocessing,
|
||||
isSelected,
|
||||
@@ -228,7 +226,7 @@ class InteractiveImportRow extends Component {
|
||||
</TableRowCellButton>
|
||||
|
||||
<TableRowCellButton
|
||||
className={styles.languages}
|
||||
className={styles.language}
|
||||
title={translate('ClickToChangeLanguage')}
|
||||
onPress={this.onSelectLanguagePress}
|
||||
>
|
||||
@@ -261,26 +259,7 @@ class InteractiveImportRow extends Component {
|
||||
|
||||
<TableRowCell>
|
||||
{
|
||||
customFormats?.length ?
|
||||
<Popover
|
||||
anchor={
|
||||
<Icon name={icons.INTERACTIVE} />
|
||||
}
|
||||
title={translate('Formats')}
|
||||
body={
|
||||
<div className={styles.customFormatTooltip}>
|
||||
<MovieFormats formats={customFormats} />
|
||||
</div>
|
||||
}
|
||||
position={tooltipPositions.LEFT}
|
||||
/> :
|
||||
null
|
||||
}
|
||||
</TableRowCell>
|
||||
|
||||
<TableRowCell>
|
||||
{
|
||||
rejections.length ?
|
||||
!!rejections.length &&
|
||||
<Popover
|
||||
anchor={
|
||||
<Icon
|
||||
@@ -303,9 +282,7 @@ class InteractiveImportRow extends Component {
|
||||
</ul>
|
||||
}
|
||||
position={tooltipPositions.LEFT}
|
||||
canFlip={false}
|
||||
/> :
|
||||
null
|
||||
/>
|
||||
}
|
||||
</TableRowCell>
|
||||
|
||||
@@ -353,7 +330,6 @@ InteractiveImportRow.propTypes = {
|
||||
languages: PropTypes.arrayOf(PropTypes.object),
|
||||
releaseGroup: PropTypes.string,
|
||||
size: PropTypes.number.isRequired,
|
||||
customFormats: PropTypes.arrayOf(PropTypes.object),
|
||||
rejections: PropTypes.arrayOf(PropTypes.object).isRequired,
|
||||
isReprocessing: PropTypes.bool,
|
||||
isSelected: PropTypes.bool,
|
||||
|
||||
@@ -76,6 +76,8 @@ class EditMovieModalContent extends Component {
|
||||
tags
|
||||
} = item;
|
||||
|
||||
console.log(qualityProfileIds);
|
||||
|
||||
return (
|
||||
<ModalContent onModalClose={onModalClose}>
|
||||
<ModalHeader>
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import PropTypes from 'prop-types';
|
||||
import React, { Component } from 'react';
|
||||
import AvailabilitySelectInput from 'Components/Form/AvailabilitySelectInput';
|
||||
import QualityProfileSelectInputConnector from 'Components/Form/QualityProfileSelectInputConnector';
|
||||
import RootFolderSelectInputConnector from 'Components/Form/RootFolderSelectInputConnector';
|
||||
import SelectInput from 'Components/Form/SelectInput';
|
||||
import SpinnerButton from 'Components/Link/SpinnerButton';
|
||||
@@ -10,7 +11,6 @@ import MoveMovieModal from 'Movie/MoveMovie/MoveMovieModal';
|
||||
import translate from 'Utilities/String/translate';
|
||||
import DeleteMovieModal from './Delete/DeleteMovieModal';
|
||||
import MovieEditorFooterLabel from './MovieEditorFooterLabel';
|
||||
import QualityProfilesModal from './QualityProfiles/QualityProfilesModal';
|
||||
import TagsModal from './Tags/TagsModal';
|
||||
import styles from './MovieEditorFooter.css';
|
||||
|
||||
@@ -26,13 +26,12 @@ class MovieEditorFooter extends Component {
|
||||
|
||||
this.state = {
|
||||
monitored: NO_CHANGE,
|
||||
qualityProfileIds: NO_CHANGE,
|
||||
minimumAvailability: NO_CHANGE,
|
||||
rootFolderPath: NO_CHANGE,
|
||||
savingTags: false,
|
||||
savingQualityProfiles: false,
|
||||
isDeleteMovieModalOpen: false,
|
||||
isTagsModalOpen: false,
|
||||
isQualityProfilesModalOpen: false,
|
||||
isConfirmMoveModalOpen: false,
|
||||
destinationRootFolder: null
|
||||
};
|
||||
@@ -47,10 +46,10 @@ class MovieEditorFooter extends Component {
|
||||
if (prevProps.isSaving && !isSaving && !saveError) {
|
||||
this.setState({
|
||||
monitored: NO_CHANGE,
|
||||
qualityProfileIds: NO_CHANGE,
|
||||
minimumAvailability: NO_CHANGE,
|
||||
rootFolderPath: NO_CHANGE,
|
||||
savingTags: false,
|
||||
savingQualityProfiles: false
|
||||
savingTags: false
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -92,17 +91,6 @@ class MovieEditorFooter extends Component {
|
||||
});
|
||||
};
|
||||
|
||||
onApplyQualityProfilesPress = (qualityProfileIds) => {
|
||||
this.setState({
|
||||
savingQualityProfiles: true,
|
||||
isQualityProfilesModalOpen: false
|
||||
});
|
||||
|
||||
this.props.onSaveSelected({
|
||||
qualityProfileIds
|
||||
});
|
||||
};
|
||||
|
||||
onDeleteSelectedPress = () => {
|
||||
this.setState({ isDeleteMovieModalOpen: true });
|
||||
};
|
||||
@@ -119,14 +107,6 @@ class MovieEditorFooter extends Component {
|
||||
this.setState({ isTagsModalOpen: false });
|
||||
};
|
||||
|
||||
onQualityProfilesPress = () => {
|
||||
this.setState({ isQualityProfilesModalOpen: true });
|
||||
};
|
||||
|
||||
onQualityProfilesModalClose = () => {
|
||||
this.setState({ isQualityProfilesModalOpen: false });
|
||||
};
|
||||
|
||||
onSaveRootFolderPress = () => {
|
||||
this.setState({
|
||||
isConfirmMoveModalOpen: false,
|
||||
@@ -167,9 +147,7 @@ class MovieEditorFooter extends Component {
|
||||
minimumAvailability,
|
||||
rootFolderPath,
|
||||
savingTags,
|
||||
savingQualityProfiles,
|
||||
isTagsModalOpen,
|
||||
isQualityProfilesModalOpen,
|
||||
isDeleteMovieModalOpen,
|
||||
isConfirmMoveModalOpen,
|
||||
destinationRootFolder
|
||||
@@ -204,14 +182,13 @@ class MovieEditorFooter extends Component {
|
||||
isSaving={isSaving && qualityProfileIds !== NO_CHANGE}
|
||||
/>
|
||||
|
||||
<SpinnerButton
|
||||
className={styles.tagsButton}
|
||||
isSpinning={isSaving && savingTags && savingQualityProfiles}
|
||||
isDisabled={!selectedCount || isOrganizingMovie}
|
||||
onPress={this.onQualityProfilesPress}
|
||||
>
|
||||
{translate('SetQualityProfiles')}
|
||||
</SpinnerButton>
|
||||
<QualityProfileSelectInputConnector
|
||||
name="qualityProfileId"
|
||||
value={qualityProfileIds}
|
||||
includeNoChange={true}
|
||||
isDisabled={!selectedCount}
|
||||
onChange={this.onInputChange}
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div className={styles.inputContainer}>
|
||||
@@ -266,7 +243,7 @@ class MovieEditorFooter extends Component {
|
||||
|
||||
<SpinnerButton
|
||||
className={styles.tagsButton}
|
||||
isSpinning={isSaving && savingTags && savingQualityProfiles}
|
||||
isSpinning={isSaving && savingTags}
|
||||
isDisabled={!selectedCount || isOrganizingMovie}
|
||||
onPress={this.onTagsPress}
|
||||
>
|
||||
@@ -294,13 +271,6 @@ class MovieEditorFooter extends Component {
|
||||
onModalClose={this.onTagsModalClose}
|
||||
/>
|
||||
|
||||
<QualityProfilesModal
|
||||
isOpen={isQualityProfilesModalOpen}
|
||||
movieIds={movieIds}
|
||||
onApplyQualityProfilesPress={this.onApplyQualityProfilesPress}
|
||||
onModalClose={this.onQualityProfilesModalClose}
|
||||
/>
|
||||
|
||||
<DeleteMovieModal
|
||||
isOpen={isDeleteMovieModalOpen}
|
||||
movieIds={movieIds}
|
||||
|
||||
@@ -1,31 +0,0 @@
|
||||
import PropTypes from 'prop-types';
|
||||
import React from 'react';
|
||||
import Modal from 'Components/Modal/Modal';
|
||||
import QualityProfilesModalContent from './QualityProfilesModalContent';
|
||||
|
||||
function QualityProfilesModal(props) {
|
||||
const {
|
||||
isOpen,
|
||||
onModalClose,
|
||||
...otherProps
|
||||
} = props;
|
||||
|
||||
return (
|
||||
<Modal
|
||||
isOpen={isOpen}
|
||||
onModalClose={onModalClose}
|
||||
>
|
||||
<QualityProfilesModalContent
|
||||
{...otherProps}
|
||||
onModalClose={onModalClose}
|
||||
/>
|
||||
</Modal>
|
||||
);
|
||||
}
|
||||
|
||||
QualityProfilesModal.propTypes = {
|
||||
isOpen: PropTypes.bool.isRequired,
|
||||
onModalClose: PropTypes.func.isRequired
|
||||
};
|
||||
|
||||
export default QualityProfilesModal;
|
||||
@@ -1,12 +0,0 @@
|
||||
.renameIcon {
|
||||
margin-left: 5px;
|
||||
}
|
||||
|
||||
.message {
|
||||
margin-top: 20px;
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
|
||||
.result {
|
||||
padding-top: 4px;
|
||||
}
|
||||
@@ -1,98 +0,0 @@
|
||||
import PropTypes from 'prop-types';
|
||||
import React, { Component } from 'react';
|
||||
import Form from 'Components/Form/Form';
|
||||
import FormGroup from 'Components/Form/FormGroup';
|
||||
import FormInputGroup from 'Components/Form/FormInputGroup';
|
||||
import FormLabel from 'Components/Form/FormLabel';
|
||||
import Button from 'Components/Link/Button';
|
||||
import ModalBody from 'Components/Modal/ModalBody';
|
||||
import ModalContent from 'Components/Modal/ModalContent';
|
||||
import ModalFooter from 'Components/Modal/ModalFooter';
|
||||
import ModalHeader from 'Components/Modal/ModalHeader';
|
||||
import { inputTypes, kinds } from 'Helpers/Props';
|
||||
import translate from 'Utilities/String/translate';
|
||||
|
||||
class QualityProfilesModalContent extends Component {
|
||||
|
||||
//
|
||||
// Lifecycle
|
||||
|
||||
constructor(props, context) {
|
||||
super(props, context);
|
||||
|
||||
this.state = {
|
||||
qualityProfileIds: []
|
||||
};
|
||||
}
|
||||
|
||||
//
|
||||
// Lifecycle
|
||||
|
||||
onInputChange = ({ name, value }) => {
|
||||
this.setState({ [name]: value });
|
||||
};
|
||||
|
||||
onApplyQualityProfilesPress = () => {
|
||||
const {
|
||||
qualityProfileIds
|
||||
} = this.state;
|
||||
|
||||
this.props.onApplyQualityProfilesPress(qualityProfileIds);
|
||||
};
|
||||
|
||||
//
|
||||
// Render
|
||||
|
||||
render() {
|
||||
const {
|
||||
onModalClose
|
||||
} = this.props;
|
||||
|
||||
const {
|
||||
qualityProfileIds
|
||||
} = this.state;
|
||||
|
||||
return (
|
||||
<ModalContent onModalClose={onModalClose}>
|
||||
<ModalHeader>
|
||||
{translate('QualityProfiles')}
|
||||
</ModalHeader>
|
||||
|
||||
<ModalBody>
|
||||
<Form>
|
||||
<FormGroup>
|
||||
<FormLabel>{translate('QualityProfiles')}</FormLabel>
|
||||
|
||||
<FormInputGroup
|
||||
type={inputTypes.QUALITY_PROFILE_SELECT}
|
||||
name="qualityProfileIds"
|
||||
value={qualityProfileIds}
|
||||
onChange={this.onInputChange}
|
||||
/>
|
||||
</FormGroup>
|
||||
</Form>
|
||||
</ModalBody>
|
||||
|
||||
<ModalFooter>
|
||||
<Button onPress={onModalClose}>
|
||||
{translate('Cancel')}
|
||||
</Button>
|
||||
|
||||
<Button
|
||||
kind={kinds.PRIMARY}
|
||||
onPress={this.onApplyQualityProfilesPress}
|
||||
>
|
||||
{translate('Apply')}
|
||||
</Button>
|
||||
</ModalFooter>
|
||||
</ModalContent>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
QualityProfilesModalContent.propTypes = {
|
||||
onModalClose: PropTypes.func.isRequired,
|
||||
onApplyQualityProfilesPress: PropTypes.func.isRequired
|
||||
};
|
||||
|
||||
export default QualityProfilesModalContent;
|
||||
@@ -62,7 +62,6 @@ class MovieHistoryRow extends Component {
|
||||
sourceTitle,
|
||||
quality,
|
||||
customFormats,
|
||||
customFormatScore,
|
||||
languages,
|
||||
qualityCutoffNotMet,
|
||||
date,
|
||||
@@ -107,7 +106,7 @@ class MovieHistoryRow extends Component {
|
||||
</TableRowCell>
|
||||
|
||||
<TableRowCell key={name}>
|
||||
{formatCustomFormatScore(customFormatScore)}
|
||||
{formatCustomFormatScore(data.customFormatScore)}
|
||||
</TableRowCell>
|
||||
|
||||
<RelativeDateCellConnector
|
||||
@@ -162,8 +161,7 @@ MovieHistoryRow.propTypes = {
|
||||
sourceTitle: PropTypes.string.isRequired,
|
||||
languages: PropTypes.arrayOf(PropTypes.object).isRequired,
|
||||
quality: PropTypes.object.isRequired,
|
||||
customFormats: PropTypes.arrayOf(PropTypes.object),
|
||||
customFormatScore: PropTypes.number.isRequired,
|
||||
customFormats: PropTypes.arrayOf(PropTypes.object).isRequired,
|
||||
qualityCutoffNotMet: PropTypes.bool.isRequired,
|
||||
date: PropTypes.string.isRequired,
|
||||
data: PropTypes.object.isRequired,
|
||||
|
||||
@@ -17,10 +17,6 @@
|
||||
font-size: 24px;
|
||||
}
|
||||
|
||||
.buttons {
|
||||
flex: 0 0 auto;
|
||||
}
|
||||
|
||||
.cloneButton {
|
||||
composes: button from '~Components/Link/IconButton.css';
|
||||
|
||||
@@ -40,10 +36,3 @@
|
||||
margin: 0;
|
||||
border: none;
|
||||
}
|
||||
|
||||
.label {
|
||||
@add-mixin truncate;
|
||||
composes: label from '~Components/Label.css';
|
||||
|
||||
max-width: 100%;
|
||||
}
|
||||
|
||||
@@ -90,7 +90,7 @@ class CustomFormat extends Component {
|
||||
{name}
|
||||
</div>
|
||||
|
||||
<div className={styles.buttons}>
|
||||
<div>
|
||||
<IconButton
|
||||
className={styles.cloneButton}
|
||||
title={translate('CloneCustomFormat')}
|
||||
@@ -124,7 +124,6 @@ class CustomFormat extends Component {
|
||||
|
||||
return (
|
||||
<Label
|
||||
className={styles.label}
|
||||
key={index}
|
||||
kind={kind}
|
||||
>
|
||||
|
||||
@@ -16,7 +16,6 @@ export const authenticationRequiredWarning = 'To prevent remote access without a
|
||||
|
||||
export const authenticationMethodOptions = [
|
||||
{ key: 'none', value: 'None', isDisabled: true },
|
||||
{ key: 'external', value: 'External', isHidden: true },
|
||||
{ key: 'basic', value: 'Basic (Browser Popup, insecure over HTTP)' },
|
||||
{ key: 'forms', value: 'Forms (Login Page)' },
|
||||
{ key: 'plex', value: 'Plex' },
|
||||
|
||||
@@ -89,7 +89,6 @@ function EditIndexerModalContent(props) {
|
||||
<FormInputGroup
|
||||
type={inputTypes.CHECK}
|
||||
name="enableRss"
|
||||
helpText={supportsRss.value ? translate('RSSHelpText') : undefined}
|
||||
helpTextWarning={supportsRss.value ? undefined : translate('RSSIsNotSupportedWithThisIndexer')}
|
||||
isDisabled={!supportsRss.value}
|
||||
{...enableRss}
|
||||
|
||||
@@ -30,7 +30,6 @@
|
||||
code {
|
||||
padding: 0 1px;
|
||||
border: 1px solid var(--borderColor);
|
||||
background-color: var(--modalCloseButtonHoverColor);
|
||||
color: var(--movieBackgroundColor);
|
||||
background-color: var(--pageBackground);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7,11 +7,11 @@
|
||||
|
||||
&:hover {
|
||||
.token {
|
||||
background-color: var(--popoverTitleBackgroundInverseColor);
|
||||
background-color: #ddd;
|
||||
}
|
||||
|
||||
.example {
|
||||
background-color: var(--popoverTitleBorderInverseColor);
|
||||
background-color: #ccc;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -27,7 +27,7 @@
|
||||
.token {
|
||||
flex: 0 0 50%;
|
||||
padding: 6px 16px;
|
||||
background-color: var(--popoverTitleBorderColor);
|
||||
background-color: #eee;
|
||||
font-family: $monoSpaceFontFamily;
|
||||
}
|
||||
|
||||
@@ -38,7 +38,7 @@
|
||||
justify-content: space-between;
|
||||
flex: 0 0 50%;
|
||||
padding: 6px 16px;
|
||||
background-color: var(--popoverTitleBackgroundColor);
|
||||
background-color: #ddd;
|
||||
|
||||
.footNote {
|
||||
padding: 2px;
|
||||
|
||||
@@ -18,7 +18,6 @@ export const certificationCountryOptions = [
|
||||
{ key: 'fr', value: 'France' },
|
||||
{ key: 'de', value: 'Germany' },
|
||||
{ key: 'gb', value: 'Great Britain' },
|
||||
{ key: 'ie', value: 'Ireland' },
|
||||
{ key: 'it', value: 'Italy' },
|
||||
{ key: 'es', value: 'Spain' },
|
||||
{ key: 'us', value: 'United States' },
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import React, { Component } from 'react';
|
||||
import { DndProvider } from 'react-dnd-multi-backend';
|
||||
import HTML5toTouch from 'react-dnd-multi-backend/dist/esm/HTML5toTouch';
|
||||
import { DndProvider } from 'react-dnd';
|
||||
import { HTML5Backend } from 'react-dnd-html5-backend';
|
||||
import Link from 'Components/Link/Link';
|
||||
import PageContent from 'Components/Page/PageContent';
|
||||
import PageContentBody from 'Components/Page/PageContentBody';
|
||||
@@ -25,7 +25,7 @@ class Profiles extends Component {
|
||||
/>
|
||||
|
||||
<PageContentBody>
|
||||
<DndProvider options={HTML5toTouch}>
|
||||
<DndProvider backend={HTML5Backend}>
|
||||
<QualityProfilesConnector />
|
||||
<DelayProfilesConnector />
|
||||
<div className={styles.addCustomFormatMessage}>
|
||||
|
||||
@@ -118,12 +118,6 @@ export const defaultState = {
|
||||
isSortable: true,
|
||||
isVisible: false
|
||||
},
|
||||
{
|
||||
name: 'year',
|
||||
label: translate('Year'),
|
||||
isSortable: true,
|
||||
isVisible: true
|
||||
},
|
||||
{
|
||||
name: 'outputPath',
|
||||
label: translate('OutputPath'),
|
||||
|
||||
@@ -201,11 +201,6 @@ export const defaultState = {
|
||||
return genreList.sort(sortByName);
|
||||
}
|
||||
},
|
||||
{
|
||||
name: 'customFormatScore',
|
||||
label: translate('CustomFormatScore'),
|
||||
type: filterBuilderTypes.NUMBER
|
||||
},
|
||||
{
|
||||
name: 'rejectionCount',
|
||||
label: translate('RejectionCount'),
|
||||
|
||||
@@ -226,8 +226,6 @@ module.exports = {
|
||||
//
|
||||
// Misc
|
||||
|
||||
progressBarFrontTextColor: white,
|
||||
progressBarBackTextColor: white,
|
||||
progressBarBackgroundColor: '#727070',
|
||||
logEventsBackgroundColor: '#2a2a2a'
|
||||
};
|
||||
|
||||
@@ -1,11 +1,7 @@
|
||||
import * as dark from './dark';
|
||||
import * as light from './light';
|
||||
|
||||
const defaultDark = window.matchMedia('(prefers-color-scheme: dark)').matches;
|
||||
const auto = defaultDark ? { ...dark } : { ...light };
|
||||
|
||||
export default {
|
||||
auto,
|
||||
light,
|
||||
dark
|
||||
};
|
||||
|
||||
@@ -202,8 +202,8 @@ module.exports = {
|
||||
popoverShadowColor: 'rgba(0, 0, 0, 0.2)',
|
||||
popoverArrowBorderColor: '#fff',
|
||||
|
||||
popoverTitleBackgroundInverseColor: '#9b9b9b',
|
||||
popoverTitleBorderInverseColor: '#bfbfbf',
|
||||
popoverTitleBackgroundInverseColor: '#595959',
|
||||
popoverTitleBorderInverseColor: '#707070',
|
||||
popoverShadowInverseColor: 'rgba(0, 0, 0, 0.2)',
|
||||
popoverArrowBorderInverseColor: 'rgba(58, 63, 81, 0.75)',
|
||||
|
||||
@@ -231,8 +231,6 @@ module.exports = {
|
||||
//
|
||||
// Misc
|
||||
|
||||
progressBarFrontTextColor: white,
|
||||
progressBarBackTextColor: darkGray,
|
||||
progressBarBackgroundColor: white,
|
||||
logEventsBackgroundColor: white
|
||||
progressBarBackgroundColor: '#fff',
|
||||
logEventsBackgroundColor: '#fff'
|
||||
};
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
function formatCustomFormatScore(input, customFormatsLength = 0) {
|
||||
|
||||
function formatCustomFormatScore(input) {
|
||||
const score = Number(input);
|
||||
|
||||
if (score > 0) {
|
||||
@@ -9,7 +10,7 @@ function formatCustomFormatScore(input, customFormatsLength = 0) {
|
||||
return score;
|
||||
}
|
||||
|
||||
return customFormatsLength > 0 ? '+0' : '';
|
||||
return '';
|
||||
}
|
||||
|
||||
export default formatCustomFormatScore;
|
||||
|
||||
13
package.json
13
package.json
@@ -8,8 +8,8 @@
|
||||
"clean": "rimraf ./_output/UI && rimraf \"**/*.js.map\"",
|
||||
"start": "webpack --watch --config ./frontend/build/webpack.config.js",
|
||||
"watch": "webpack --watch --config ./frontend/build/webpack.config.js",
|
||||
"lint": "eslint --config frontend/.eslintrc.js --ignore-path frontend/.eslintignore frontend/",
|
||||
"lint-fix": "yarn lint --fix",
|
||||
"lint": "esprint check",
|
||||
"lint-fix": "esprint check --fix",
|
||||
"stylelint-linux": "stylelint $(find frontend -name '*.css') --config frontend/.stylelintrc",
|
||||
"stylelint-windows": "stylelint frontend/**/*.css --config frontend/.stylelintrc"
|
||||
},
|
||||
@@ -108,11 +108,12 @@
|
||||
"eslint-plugin-json": "3.1.0",
|
||||
"eslint-plugin-react": "7.29.4",
|
||||
"eslint-plugin-react-hooks": "4.6.0",
|
||||
"eslint-plugin-simple-import-sort": "8.0.0",
|
||||
"eslint-plugin-simple-import-sort": "7.0.0",
|
||||
"esprint": "3.3.0",
|
||||
"file-loader": "6.2.0",
|
||||
"filemanager-webpack-plugin": "5.0.0",
|
||||
"html-webpack-plugin": "5.3.1",
|
||||
"loader-utils": "^3.2.1",
|
||||
"loader-utils": "^2.0.0",
|
||||
"mini-css-extract-plugin": "1.5.0",
|
||||
"postcss": "8.2.12",
|
||||
"postcss-color-function": "4.1.0",
|
||||
@@ -133,9 +134,5 @@
|
||||
"webpack-cli": "4.9.1",
|
||||
"webpack-livereload-plugin": "3.0.2",
|
||||
"worker-loader": "3.0.8"
|
||||
},
|
||||
"volta": {
|
||||
"node": "16.17.0",
|
||||
"yarn": "1.22.19"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,3 +0,0 @@
|
||||
is_global = true
|
||||
|
||||
dotnet_diagnostic.CA1014.severity = none
|
||||
@@ -1,9 +1,7 @@
|
||||
<Project>
|
||||
<!-- Common to all Radarr Projects -->
|
||||
<PropertyGroup>
|
||||
<AnalysisLevel>6.0-all</AnalysisLevel>
|
||||
<TreatWarningsAsErrors>true</TreatWarningsAsErrors>
|
||||
<EnforceCodeStyleInBuild>true</EnforceCodeStyleInBuild>
|
||||
<ErrorOnDuplicatePublishOutputFiles>false</ErrorOnDuplicatePublishOutputFiles>
|
||||
|
||||
<PlatformTarget>AnyCPU</PlatformTarget>
|
||||
|
||||
@@ -1,25 +0,0 @@
|
||||
using System.Globalization;
|
||||
using FluentAssertions;
|
||||
using NUnit.Framework;
|
||||
using NzbDrone.Common.Extensions;
|
||||
|
||||
namespace NzbDrone.Common.Test.ExtensionTests.StringExtensionTests
|
||||
{
|
||||
[TestFixture]
|
||||
public class IsValidIPAddressFixture
|
||||
{
|
||||
[TestCase("192.168.0.1")]
|
||||
[TestCase("::1")]
|
||||
[TestCase("2001:db8:4006:812::200e")]
|
||||
public void should_validate_ip_address(string input)
|
||||
{
|
||||
input.IsValidIpAddress().Should().BeTrue();
|
||||
}
|
||||
|
||||
[TestCase("sonarr.tv")]
|
||||
public void should_not_parse_non_ip_address(string input)
|
||||
{
|
||||
input.IsValidIpAddress().Should().BeFalse();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
using FluentAssertions;
|
||||
using FluentAssertions;
|
||||
using NUnit.Framework;
|
||||
using NzbDrone.Common.Http;
|
||||
using NzbDrone.Test.Common;
|
||||
@@ -10,7 +10,6 @@ namespace NzbDrone.Common.Test.Http
|
||||
[TestCase("abc://my_host.com:8080/root/api/")]
|
||||
[TestCase("abc://my_host.com:8080//root/api/")]
|
||||
[TestCase("abc://my_host.com:8080/root//api/")]
|
||||
[TestCase("abc://[::1]:8080/root//api/")]
|
||||
public void should_parse(string uri)
|
||||
{
|
||||
var newUri = new HttpUri(uri);
|
||||
|
||||
@@ -356,7 +356,7 @@ namespace NzbDrone.Common.Disk
|
||||
}
|
||||
}
|
||||
|
||||
public virtual string GetPathRoot(string path)
|
||||
public string GetPathRoot(string path)
|
||||
{
|
||||
Ensure.That(path, () => path).IsValidPath();
|
||||
|
||||
|
||||
@@ -11,7 +11,6 @@ namespace NzbDrone.Common.EnvironmentInfo
|
||||
public interface IAppFolderFactory
|
||||
{
|
||||
void Register();
|
||||
void SetPermissions();
|
||||
}
|
||||
|
||||
public class AppFolderFactory : IAppFolderFactory
|
||||
@@ -59,7 +58,7 @@ namespace NzbDrone.Common.EnvironmentInfo
|
||||
InitializeMonoApplicationData();
|
||||
}
|
||||
|
||||
public void SetPermissions()
|
||||
private void SetPermissions()
|
||||
{
|
||||
try
|
||||
{
|
||||
|
||||
@@ -9,7 +9,6 @@ namespace NzbDrone.Common.EnvironmentInfo
|
||||
bool IsAdmin { get; }
|
||||
bool IsWindowsService { get; }
|
||||
bool IsWindowsTray { get; }
|
||||
bool IsStarting { get; set; }
|
||||
bool IsExiting { get; set; }
|
||||
bool IsTray { get; }
|
||||
RuntimeMode Mode { get; }
|
||||
|
||||
@@ -19,7 +19,6 @@ namespace NzbDrone.Common.EnvironmentInfo
|
||||
_logger = logger;
|
||||
|
||||
IsWindowsService = hostLifetime is WindowsServiceLifetime;
|
||||
IsStarting = true;
|
||||
|
||||
// net6.0 will return Radarr.dll for entry assembly, we need the actual
|
||||
// executable name (Radarr on linux). On mono this will return the location of
|
||||
@@ -83,7 +82,6 @@ namespace NzbDrone.Common.EnvironmentInfo
|
||||
|
||||
public bool IsWindowsService { get; private set; }
|
||||
|
||||
public bool IsStarting { get; set; }
|
||||
public bool IsExiting { get; set; }
|
||||
public bool IsTray
|
||||
{
|
||||
|
||||
@@ -7,50 +7,34 @@ namespace NzbDrone.Common.Extensions
|
||||
{
|
||||
public static bool IsLocalAddress(this IPAddress ipAddress)
|
||||
{
|
||||
// Map back to IPv4 if mapped to IPv6, for example "::ffff:1.2.3.4" to "1.2.3.4".
|
||||
if (ipAddress.IsIPv4MappedToIPv6)
|
||||
if (ipAddress.IsIPv6LinkLocal)
|
||||
{
|
||||
ipAddress = ipAddress.MapToIPv4();
|
||||
return true;
|
||||
}
|
||||
|
||||
// Checks loopback ranges for both IPv4 and IPv6.
|
||||
if (IPAddress.IsLoopback(ipAddress))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
// IPv4
|
||||
if (ipAddress.AddressFamily == AddressFamily.InterNetwork)
|
||||
{
|
||||
return IsLocalIPv4(ipAddress.GetAddressBytes());
|
||||
}
|
||||
|
||||
// IPv6
|
||||
if (ipAddress.AddressFamily == AddressFamily.InterNetworkV6)
|
||||
{
|
||||
return ipAddress.IsIPv6LinkLocal ||
|
||||
ipAddress.IsIPv6UniqueLocal ||
|
||||
ipAddress.IsIPv6SiteLocal;
|
||||
byte[] bytes = ipAddress.GetAddressBytes();
|
||||
switch (bytes[0])
|
||||
{
|
||||
case 10:
|
||||
case 127:
|
||||
return true;
|
||||
case 172:
|
||||
return bytes[1] < 32 && bytes[1] >= 16;
|
||||
case 192:
|
||||
return bytes[1] == 168;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private static bool IsLocalIPv4(byte[] ipv4Bytes)
|
||||
{
|
||||
// Link local (no IP assigned by DHCP): 169.254.0.0 to 169.254.255.255 (169.254.0.0/16)
|
||||
bool IsLinkLocal() => ipv4Bytes[0] == 169 && ipv4Bytes[1] == 254;
|
||||
|
||||
// Class A private range: 10.0.0.0 – 10.255.255.255 (10.0.0.0/8)
|
||||
bool IsClassA() => ipv4Bytes[0] == 10;
|
||||
|
||||
// Class B private range: 172.16.0.0 – 172.31.255.255 (172.16.0.0/12)
|
||||
bool IsClassB() => ipv4Bytes[0] == 172 && ipv4Bytes[1] >= 16 && ipv4Bytes[1] <= 31;
|
||||
|
||||
// Class C private range: 192.168.0.0 – 192.168.255.255 (192.168.0.0/16)
|
||||
bool IsClassC() => ipv4Bytes[0] == 192 && ipv4Bytes[1] == 168;
|
||||
|
||||
return IsLinkLocal() || IsClassA() || IsClassC() || IsClassB();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,8 +2,6 @@ using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Globalization;
|
||||
using System.Linq;
|
||||
using System.Net;
|
||||
using System.Net.Sockets;
|
||||
using System.Text;
|
||||
using System.Text.RegularExpressions;
|
||||
|
||||
@@ -131,7 +129,7 @@ namespace NzbDrone.Common.Extensions
|
||||
|
||||
public static string WrapInQuotes(this string text)
|
||||
{
|
||||
if (!text.Contains(' '))
|
||||
if (!text.Contains(" "))
|
||||
{
|
||||
return text;
|
||||
}
|
||||
@@ -194,30 +192,5 @@ namespace NzbDrone.Common.Extensions
|
||||
.Replace("'", "%27")
|
||||
.Replace("%7E", "~");
|
||||
}
|
||||
|
||||
public static bool IsValidIpAddress(this string value)
|
||||
{
|
||||
if (!IPAddress.TryParse(value, out var parsedAddress))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (parsedAddress.Equals(IPAddress.Parse("255.255.255.255")))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (parsedAddress.IsIPv6Multicast)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return parsedAddress.AddressFamily == AddressFamily.InterNetwork || parsedAddress.AddressFamily == AddressFamily.InterNetworkV6;
|
||||
}
|
||||
|
||||
public static string ToUrlHost(this string input)
|
||||
{
|
||||
return input.Contains(':') ? $"[{input}]" : input;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -216,7 +216,7 @@ namespace NzbDrone.Common.Http.Dispatchers
|
||||
}
|
||||
}
|
||||
|
||||
private static void AddContentHeader(HttpRequestMessage request, string header, string value)
|
||||
private void AddContentHeader(HttpRequestMessage request, string header, string value)
|
||||
{
|
||||
var headers = request.Content?.Headers;
|
||||
if (headers == null)
|
||||
|
||||
@@ -8,7 +8,7 @@ namespace NzbDrone.Common.Http
|
||||
{
|
||||
public class HttpUri : IEquatable<HttpUri>
|
||||
{
|
||||
private static readonly Regex RegexUri = new Regex(@"^(?:(?<scheme>[a-z]+):)?(?://(?<host>[-_A-Z0-9.]+|\[[[A-F0-9:]+\])(?::(?<port>[0-9]{1,5}))?)?(?<path>(?:(?:(?<=^)|/+)[^/?#\r\n]+)+/*|/+)?(?:\?(?<query>[^#\r\n]*))?(?:\#(?<fragment>.*))?$", RegexOptions.Compiled | RegexOptions.IgnoreCase);
|
||||
private static readonly Regex RegexUri = new Regex(@"^(?:(?<scheme>[a-z]+):)?(?://(?<host>[-_A-Z0-9.]+)(?::(?<port>[0-9]{1,5}))?)?(?<path>(?:(?:(?<=^)|/+)[^/?#\r\n]+)+/*|/+)?(?:\?(?<query>[^#\r\n]*))?(?:\#(?<fragment>.*))?$", RegexOptions.Compiled | RegexOptions.IgnoreCase);
|
||||
|
||||
private readonly string _uri;
|
||||
public string FullUri => _uri;
|
||||
@@ -70,8 +70,6 @@ namespace NzbDrone.Common.Http
|
||||
|
||||
private void Parse()
|
||||
{
|
||||
var parseSuccess = Uri.TryCreate(_uri, UriKind.RelativeOrAbsolute, out var uri);
|
||||
|
||||
var match = RegexUri.Match(_uri);
|
||||
|
||||
var scheme = match.Groups["scheme"];
|
||||
@@ -81,7 +79,7 @@ namespace NzbDrone.Common.Http
|
||||
var query = match.Groups["query"];
|
||||
var fragment = match.Groups["fragment"];
|
||||
|
||||
if (!parseSuccess || (scheme.Success && !host.Success && path.Success))
|
||||
if (!match.Success || (scheme.Success && !host.Success && path.Success))
|
||||
{
|
||||
throw new ArgumentException("Uri didn't match expected pattern: " + _uri);
|
||||
}
|
||||
@@ -170,7 +168,7 @@ namespace NzbDrone.Common.Http
|
||||
|
||||
if (baseSlashIndex >= 0)
|
||||
{
|
||||
return $"{basePath.AsSpan(0, baseSlashIndex)}/{relativePath}";
|
||||
return basePath.Substring(0, baseSlashIndex) + "/" + relativePath;
|
||||
}
|
||||
|
||||
return relativePath;
|
||||
|
||||
@@ -8,7 +8,6 @@ using System.Threading;
|
||||
using NLog;
|
||||
using NLog.Common;
|
||||
using NLog.Targets;
|
||||
using Npgsql;
|
||||
using NzbDrone.Common.EnvironmentInfo;
|
||||
using NzbDrone.Common.Extensions;
|
||||
using Sentry;
|
||||
@@ -35,14 +34,6 @@ namespace NzbDrone.Common.Instrumentation.Sentry
|
||||
SQLiteErrorCode.Auth
|
||||
};
|
||||
|
||||
private static readonly HashSet<string> FilteredPostgresErrorCodes = new HashSet<string>
|
||||
{
|
||||
PostgresErrorCodes.OutOfMemory,
|
||||
PostgresErrorCodes.TooManyConnections,
|
||||
PostgresErrorCodes.DiskFull,
|
||||
PostgresErrorCodes.ProgramLimitExceeded
|
||||
};
|
||||
|
||||
// use string and not Type so we don't need a reference to the project
|
||||
// where these are defined
|
||||
private static readonly HashSet<string> FilteredExceptionTypeNames = new HashSet<string>
|
||||
@@ -259,19 +250,6 @@ namespace NzbDrone.Common.Instrumentation.Sentry
|
||||
isSentry = false;
|
||||
}
|
||||
|
||||
var pgEx = logEvent.Exception as PostgresException;
|
||||
if (pgEx != null && FilteredPostgresErrorCodes.Contains(pgEx.SqlState))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// We don't care about transient network and timeout errors
|
||||
var npgEx = logEvent.Exception as NpgsqlException;
|
||||
if (npgEx != null && npgEx.IsTransient)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (FilteredExceptionTypeNames.Contains(ex.GetType().Name))
|
||||
{
|
||||
isSentry = false;
|
||||
|
||||
@@ -7,10 +7,9 @@
|
||||
<PackageReference Include="DryIoc.dll" Version="5.3.0" />
|
||||
<PackageReference Include="Microsoft.Extensions.DependencyInjection" Version="6.0.0" />
|
||||
<PackageReference Include="Microsoft.Extensions.Hosting.WindowsServices" Version="6.0.0" />
|
||||
<PackageReference Include="Newtonsoft.Json" Version="13.0.2" />
|
||||
<PackageReference Include="Newtonsoft.Json" Version="13.0.1" />
|
||||
<PackageReference Include="NLog" Version="5.0.1" />
|
||||
<PackageReference Include="NLog.Extensions.Logging" Version="5.0.0" />
|
||||
<PackageReference Include="Npgsql" Version="5.0.11" />
|
||||
<PackageReference Include="Sentry" Version="3.23.1" />
|
||||
<PackageReference Include="NLog.Targets.Syslog" Version="7.0.0" />
|
||||
<PackageReference Include="SharpZipLib" Version="1.3.3" />
|
||||
|
||||
@@ -64,7 +64,7 @@ namespace NzbDrone.Common
|
||||
|
||||
var args = $"create {serviceName} " +
|
||||
$"DisplayName= \"{serviceName}\" " +
|
||||
$"binpath= \"{Environment.ProcessPath}\" " +
|
||||
$"binpath= \"{Process.GetCurrentProcess().MainModule.FileName}\" " +
|
||||
"start= auto " +
|
||||
"depend= EventLog/Tcpip/http " +
|
||||
"obj= \"NT AUTHORITY\\LocalService\"";
|
||||
|
||||
@@ -19,7 +19,7 @@ namespace NzbDrone.Common.TPL
|
||||
private readonly int _maxDegreeOfParallelism;
|
||||
|
||||
/// <summary>Whether the scheduler is currently processing work items.</summary>
|
||||
private int _delegatesQueuedOrRunning;
|
||||
private int _delegatesQueuedOrRunning = 0;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes an instance of the LimitedConcurrencyLevelTaskScheduler class with the
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
using System;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using NUnit.Framework;
|
||||
@@ -9,7 +9,7 @@ using NzbDrone.Core.Test.Framework;
|
||||
namespace NzbDrone.Core.Test.CustomFormats
|
||||
{
|
||||
[TestFixture]
|
||||
public class CustomFormatsTestHelpers : CoreTest
|
||||
public class CustomFormatsFixture : CoreTest
|
||||
{
|
||||
private static List<CustomFormat> _customFormats { get; set; }
|
||||
|
||||
@@ -15,7 +15,7 @@ namespace NzbDrone.Core.Test.Datastore.Migration
|
||||
[TestFixture]
|
||||
public class custom_formatsFixture : MigrationTest<add_custom_formats>
|
||||
{
|
||||
public static Dictionary<int, int> QualityToDefinition;
|
||||
public static Dictionary<int, int> QualityToDefinition = null;
|
||||
|
||||
public void AddDefaultProfile(add_custom_formats m, string name, Quality cutoff, params Quality[] allowed)
|
||||
{
|
||||
|
||||
@@ -46,14 +46,14 @@ namespace NzbDrone.Core.Test.DecisionEngineTests
|
||||
ParsedMovieInfo = new ParsedMovieInfo { Quality = new QualityModel(Quality.DVD, new Revision(version: 2)) },
|
||||
};
|
||||
|
||||
CustomFormatsTestHelpers.GivenCustomFormats(_format1, _format2);
|
||||
CustomFormatsFixture.GivenCustomFormats(_format1, _format2);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void should_allow_if_format_score_greater_than_min()
|
||||
{
|
||||
_remoteMovie.CustomFormats = new List<CustomFormat> { _format1 };
|
||||
_remoteMovie.Movie.Profile.FormatItems = CustomFormatsTestHelpers.GetSampleFormatItems(_format1.Name);
|
||||
_remoteMovie.Movie.Profile.FormatItems = CustomFormatsFixture.GetSampleFormatItems(_format1.Name);
|
||||
_remoteMovie.CustomFormatScore = _remoteMovie.Movie.Profile.CalculateCustomFormatScore(_remoteMovie.CustomFormats);
|
||||
|
||||
Subject.IsSatisfiedBy(_remoteMovie, null).Should().OnlyContain(x => x.Accepted);
|
||||
@@ -63,7 +63,7 @@ namespace NzbDrone.Core.Test.DecisionEngineTests
|
||||
public void should_deny_if_format_score_not_greater_than_min()
|
||||
{
|
||||
_remoteMovie.CustomFormats = new List<CustomFormat> { _format2 };
|
||||
_remoteMovie.Movie.Profile.FormatItems = CustomFormatsTestHelpers.GetSampleFormatItems(_format1.Name);
|
||||
_remoteMovie.Movie.Profile.FormatItems = CustomFormatsFixture.GetSampleFormatItems(_format1.Name);
|
||||
_remoteMovie.CustomFormatScore = _remoteMovie.Movie.Profile.CalculateCustomFormatScore(_remoteMovie.CustomFormats);
|
||||
|
||||
Console.WriteLine(_remoteMovie.CustomFormatScore);
|
||||
@@ -76,7 +76,7 @@ namespace NzbDrone.Core.Test.DecisionEngineTests
|
||||
public void should_deny_if_format_score_not_greater_than_min_2()
|
||||
{
|
||||
_remoteMovie.CustomFormats = new List<CustomFormat> { _format2, _format1 };
|
||||
_remoteMovie.Movie.Profile.FormatItems = CustomFormatsTestHelpers.GetSampleFormatItems(_format1.Name);
|
||||
_remoteMovie.Movie.Profile.FormatItems = CustomFormatsFixture.GetSampleFormatItems(_format1.Name);
|
||||
_remoteMovie.CustomFormatScore = _remoteMovie.Movie.Profile.CalculateCustomFormatScore(_remoteMovie.CustomFormats);
|
||||
|
||||
Subject.IsSatisfiedBy(_remoteMovie, null).Should().OnlyContain(x => !x.Accepted);
|
||||
@@ -86,7 +86,7 @@ namespace NzbDrone.Core.Test.DecisionEngineTests
|
||||
public void should_allow_if_all_format_is_defined_in_profile()
|
||||
{
|
||||
_remoteMovie.CustomFormats = new List<CustomFormat> { _format2, _format1 };
|
||||
_remoteMovie.Movie.Profile.FormatItems = CustomFormatsTestHelpers.GetSampleFormatItems(_format1.Name, _format2.Name);
|
||||
_remoteMovie.Movie.Profile.FormatItems = CustomFormatsFixture.GetSampleFormatItems(_format1.Name, _format2.Name);
|
||||
_remoteMovie.CustomFormatScore = _remoteMovie.Movie.Profile.CalculateCustomFormatScore(_remoteMovie.CustomFormats);
|
||||
|
||||
Subject.IsSatisfiedBy(_remoteMovie, null).Should().OnlyContain(x => x.Accepted);
|
||||
@@ -96,7 +96,7 @@ namespace NzbDrone.Core.Test.DecisionEngineTests
|
||||
public void should_deny_if_no_format_was_parsed_and_min_score_positive()
|
||||
{
|
||||
_remoteMovie.CustomFormats = new List<CustomFormat> { };
|
||||
_remoteMovie.Movie.Profile.FormatItems = CustomFormatsTestHelpers.GetSampleFormatItems(_format1.Name, _format2.Name);
|
||||
_remoteMovie.Movie.Profile.FormatItems = CustomFormatsFixture.GetSampleFormatItems(_format1.Name, _format2.Name);
|
||||
_remoteMovie.CustomFormatScore = _remoteMovie.Movie.Profile.CalculateCustomFormatScore(_remoteMovie.CustomFormats);
|
||||
|
||||
Subject.IsSatisfiedBy(_remoteMovie, null).Should().OnlyContain(x => !x.Accepted);
|
||||
@@ -106,7 +106,7 @@ namespace NzbDrone.Core.Test.DecisionEngineTests
|
||||
public void should_allow_if_no_format_was_parsed_min_score_is_zero()
|
||||
{
|
||||
_remoteMovie.CustomFormats = new List<CustomFormat> { };
|
||||
_remoteMovie.Movie.Profile.FormatItems = CustomFormatsTestHelpers.GetSampleFormatItems(_format1.Name, _format2.Name);
|
||||
_remoteMovie.Movie.Profile.FormatItems = CustomFormatsFixture.GetSampleFormatItems(_format1.Name, _format2.Name);
|
||||
_remoteMovie.Movie.Profile.MinFormatScore = 0;
|
||||
_remoteMovie.CustomFormatScore = _remoteMovie.Movie.Profile.CalculateCustomFormatScore(_remoteMovie.CustomFormats);
|
||||
|
||||
|
||||
@@ -40,8 +40,8 @@ namespace NzbDrone.Core.Test.DecisionEngineTests
|
||||
|
||||
private void GivenProfile(Profile profile)
|
||||
{
|
||||
CustomFormatsTestHelpers.GivenCustomFormats();
|
||||
profile.FormatItems = CustomFormatsTestHelpers.GetSampleFormatItems();
|
||||
CustomFormatsFixture.GivenCustomFormats();
|
||||
profile.FormatItems = CustomFormatsFixture.GetSampleFormatItems();
|
||||
profile.MinFormatScore = 0;
|
||||
_remoteMovie.Movie.Profile = profile;
|
||||
|
||||
@@ -74,7 +74,7 @@ namespace NzbDrone.Core.Test.DecisionEngineTests
|
||||
{
|
||||
_customFormat = new CustomFormat("My Format", new ResolutionSpecification { Value = (int)Resolution.R1080p }) { Id = 1 };
|
||||
|
||||
CustomFormatsTestHelpers.GivenCustomFormats(_customFormat);
|
||||
CustomFormatsFixture.GivenCustomFormats(_customFormat);
|
||||
}
|
||||
|
||||
[Test]
|
||||
@@ -157,7 +157,7 @@ namespace NzbDrone.Core.Test.DecisionEngineTests
|
||||
Cutoff = Quality.HDTV720p.Id,
|
||||
Items = Qualities.QualityFixture.GetDefaultQualities(),
|
||||
MinFormatScore = 0,
|
||||
FormatItems = CustomFormatsTestHelpers.GetSampleFormatItems("My Format"),
|
||||
FormatItems = CustomFormatsFixture.GetSampleFormatItems("My Format"),
|
||||
UpgradeAllowed = true
|
||||
});
|
||||
|
||||
|
||||
@@ -38,14 +38,14 @@ namespace NzbDrone.Core.Test.DecisionEngineTests
|
||||
Mocker.Resolve<UpgradableSpecification>();
|
||||
_upgradeHistory = Mocker.Resolve<HistorySpecification>();
|
||||
|
||||
CustomFormatsTestHelpers.GivenCustomFormats();
|
||||
CustomFormatsFixture.GivenCustomFormats();
|
||||
|
||||
_fakeMovie = Builder<Movie>.CreateNew()
|
||||
.With(c => c.Profile = new Profile
|
||||
{
|
||||
Items = Qualities.QualityFixture.GetDefaultQualities(),
|
||||
Cutoff = Quality.Bluray1080p.Id,
|
||||
FormatItems = CustomFormatsTestHelpers.GetSampleFormatItems("None"),
|
||||
FormatItems = CustomFormatsFixture.GetSampleFormatItems("None"),
|
||||
MinFormatScore = 0,
|
||||
UpgradeAllowed = true
|
||||
})
|
||||
@@ -66,7 +66,7 @@ namespace NzbDrone.Core.Test.DecisionEngineTests
|
||||
.Returns(true);
|
||||
|
||||
Mocker.GetMock<ICustomFormatCalculationService>()
|
||||
.Setup(x => x.ParseCustomFormat(It.IsAny<MovieHistory>(), It.IsAny<Movie>()))
|
||||
.Setup(x => x.ParseCustomFormat(It.IsAny<MovieHistory>()))
|
||||
.Returns(new List<CustomFormat>());
|
||||
}
|
||||
|
||||
@@ -163,7 +163,7 @@ namespace NzbDrone.Core.Test.DecisionEngineTests
|
||||
{
|
||||
Items = Qualities.QualityFixture.GetDefaultQualities(),
|
||||
Cutoff = Quality.Bluray1080p.Id,
|
||||
FormatItems = CustomFormatsTestHelpers.GetSampleFormatItems(),
|
||||
FormatItems = CustomFormatsFixture.GetSampleFormatItems(),
|
||||
MinFormatScore = 0
|
||||
};
|
||||
|
||||
@@ -171,7 +171,7 @@ namespace NzbDrone.Core.Test.DecisionEngineTests
|
||||
_upgradableQuality = new QualityModel(Quality.WEBDL1080p, new Revision(version: 1));
|
||||
|
||||
Mocker.GetMock<ICustomFormatCalculationService>()
|
||||
.Setup(x => x.ParseCustomFormat(It.IsAny<MovieHistory>(), It.IsAny<Movie>()))
|
||||
.Setup(x => x.ParseCustomFormat(It.IsAny<MovieHistory>()))
|
||||
.Returns(new List<CustomFormat>());
|
||||
|
||||
GivenMostRecentForEpisode(FIRST_EPISODE_ID, string.Empty, _upgradableQuality, DateTime.UtcNow, MovieHistoryEventType.Grabbed);
|
||||
@@ -186,7 +186,7 @@ namespace NzbDrone.Core.Test.DecisionEngineTests
|
||||
{
|
||||
Items = Qualities.QualityFixture.GetDefaultQualities(),
|
||||
Cutoff = Quality.WEBDL1080p.Id,
|
||||
FormatItems = CustomFormatsTestHelpers.GetSampleFormatItems(),
|
||||
FormatItems = CustomFormatsFixture.GetSampleFormatItems(),
|
||||
MinFormatScore = 0
|
||||
};
|
||||
|
||||
@@ -221,7 +221,7 @@ namespace NzbDrone.Core.Test.DecisionEngineTests
|
||||
{
|
||||
Items = Qualities.QualityFixture.GetDefaultQualities(),
|
||||
Cutoff = Quality.WEBDL1080p.Id,
|
||||
FormatItems = CustomFormatsTestHelpers.GetSampleFormatItems(),
|
||||
FormatItems = CustomFormatsFixture.GetSampleFormatItems(),
|
||||
MinFormatScore = 0
|
||||
};
|
||||
|
||||
|
||||
@@ -41,17 +41,17 @@ namespace NzbDrone.Core.Test.DecisionEngineTests
|
||||
|
||||
private void WithEnglishRelease()
|
||||
{
|
||||
_remoteMovie.Languages = new List<Language> { Language.English };
|
||||
_remoteMovie.ParsedMovieInfo.Languages = new List<Language> { Language.English };
|
||||
}
|
||||
|
||||
private void WithGermanRelease()
|
||||
{
|
||||
_remoteMovie.Languages = new List<Language> { Language.German };
|
||||
_remoteMovie.ParsedMovieInfo.Languages = new List<Language> { Language.German };
|
||||
}
|
||||
|
||||
private void WithFrenchRelease()
|
||||
{
|
||||
_remoteMovie.Languages = new List<Language> { Language.French };
|
||||
_remoteMovie.ParsedMovieInfo.Languages = new List<Language> { Language.French };
|
||||
}
|
||||
|
||||
[Test]
|
||||
|
||||
@@ -37,7 +37,7 @@ namespace NzbDrone.Core.Test.DecisionEngineTests
|
||||
_customFormat1 = new CustomFormat("My Format 1", new LanguageSpecification { Value = (int)Language.English }) { Id = 1 };
|
||||
_customFormat2 = new CustomFormat("My Format 2", new LanguageSpecification { Value = (int)Language.French }) { Id = 2 };
|
||||
|
||||
CustomFormatsTestHelpers.GivenCustomFormats(_customFormat1, _customFormat2);
|
||||
CustomFormatsFixture.GivenCustomFormats(_customFormat1, _customFormat2);
|
||||
|
||||
Mocker.GetMock<IQualityDefinitionService>()
|
||||
.Setup(s => s.Get(It.IsAny<Quality>()))
|
||||
@@ -62,7 +62,7 @@ namespace NzbDrone.Core.Test.DecisionEngineTests
|
||||
remoteMovie.Movie = Builder<Movie>.CreateNew().With(m => m.Profile = new Profile
|
||||
{
|
||||
Items = Qualities.QualityFixture.GetDefaultQualities(),
|
||||
FormatItems = CustomFormatsTestHelpers.GetSampleFormatItems(_customFormat1.Name, _customFormat2.Name),
|
||||
FormatItems = CustomFormatsFixture.GetSampleFormatItems(_customFormat1.Name, _customFormat2.Name),
|
||||
MinFormatScore = 0
|
||||
})
|
||||
.With(m => m.Title = "A Movie")
|
||||
|
||||
@@ -48,7 +48,7 @@ namespace NzbDrone.Core.Test.DecisionEngineTests
|
||||
[SetUp]
|
||||
public void Setup()
|
||||
{
|
||||
CustomFormatsTestHelpers.GivenCustomFormats(_customFormat1, _customFormat2);
|
||||
CustomFormatsFixture.GivenCustomFormats(_customFormat1, _customFormat2);
|
||||
}
|
||||
|
||||
private void GivenAutoDownloadPropers(ProperDownloadTypes type)
|
||||
@@ -73,7 +73,7 @@ namespace NzbDrone.Core.Test.DecisionEngineTests
|
||||
var profile = new Profile
|
||||
{
|
||||
Items = Qualities.QualityFixture.GetDefaultQualities(),
|
||||
FormatItems = CustomFormatsTestHelpers.GetSampleFormatItems(_customFormat1.Name, _customFormat2.Name),
|
||||
FormatItems = CustomFormatsFixture.GetSampleFormatItems(_customFormat1.Name, _customFormat2.Name),
|
||||
MinFormatScore = 0
|
||||
};
|
||||
|
||||
|
||||
@@ -32,13 +32,13 @@ namespace NzbDrone.Core.Test.DecisionEngineTests
|
||||
{
|
||||
Mocker.Resolve<UpgradableSpecification>();
|
||||
|
||||
CustomFormatsTestHelpers.GivenCustomFormats();
|
||||
CustomFormatsFixture.GivenCustomFormats();
|
||||
|
||||
_movie = Builder<Movie>.CreateNew()
|
||||
.With(e => e.Profile = new Profile
|
||||
{
|
||||
Items = Qualities.QualityFixture.GetDefaultQualities(),
|
||||
FormatItems = CustomFormatsTestHelpers.GetSampleFormatItems(),
|
||||
FormatItems = CustomFormatsFixture.GetSampleFormatItems(),
|
||||
MinFormatScore = 0,
|
||||
UpgradeAllowed = true
|
||||
})
|
||||
@@ -58,7 +58,7 @@ namespace NzbDrone.Core.Test.DecisionEngineTests
|
||||
.Build();
|
||||
|
||||
Mocker.GetMock<ICustomFormatCalculationService>()
|
||||
.Setup(x => x.ParseCustomFormat(It.IsAny<RemoteMovie>(), It.IsAny<long>()))
|
||||
.Setup(x => x.ParseCustomFormat(It.IsAny<ParsedMovieInfo>(), _movie))
|
||||
.Returns(new List<CustomFormat>());
|
||||
}
|
||||
|
||||
|
||||
@@ -1,209 +0,0 @@
|
||||
using System.Collections.Generic;
|
||||
using FluentAssertions;
|
||||
using NUnit.Framework;
|
||||
using NzbDrone.Core.CustomFormats;
|
||||
using NzbDrone.Core.DecisionEngine.Specifications;
|
||||
using NzbDrone.Core.Profiles;
|
||||
using NzbDrone.Core.Qualities;
|
||||
using NzbDrone.Core.Test.Framework;
|
||||
|
||||
namespace NzbDrone.Core.Test.DecisionEngineTests
|
||||
{
|
||||
[TestFixture]
|
||||
public class UpgradeAllowedSpecificationFixture : CoreTest<UpgradableSpecification>
|
||||
{
|
||||
private CustomFormat _customFormatOne;
|
||||
private CustomFormat _customFormatTwo;
|
||||
private Profile _qualityProfile;
|
||||
|
||||
[SetUp]
|
||||
public void Setup()
|
||||
{
|
||||
_customFormatOne = new CustomFormat
|
||||
{
|
||||
Id = 1,
|
||||
Name = "One"
|
||||
};
|
||||
_customFormatTwo = new CustomFormat
|
||||
{
|
||||
Id = 2,
|
||||
Name = "Two"
|
||||
};
|
||||
|
||||
_qualityProfile = new Profile
|
||||
{
|
||||
Cutoff = Quality.Bluray1080p.Id,
|
||||
Items = Qualities.QualityFixture.GetDefaultQualities(),
|
||||
UpgradeAllowed = false,
|
||||
CutoffFormatScore = 100,
|
||||
FormatItems = new List<ProfileFormatItem>
|
||||
{
|
||||
new ProfileFormatItem
|
||||
{
|
||||
Format = _customFormatOne,
|
||||
Score = 50
|
||||
},
|
||||
new ProfileFormatItem
|
||||
{
|
||||
Format = _customFormatTwo,
|
||||
Score = 100
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void should_return_false_when_quality_is_better_custom_formats_are_the_same_and_upgrading_is_not_allowed()
|
||||
{
|
||||
_qualityProfile.UpgradeAllowed = false;
|
||||
|
||||
Subject.IsUpgradeAllowed(
|
||||
_qualityProfile,
|
||||
new QualityModel(Quality.DVD),
|
||||
new List<CustomFormat>(),
|
||||
new QualityModel(Quality.Bluray1080p),
|
||||
new List<CustomFormat>())
|
||||
.Should().BeFalse();
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void should_return_false_when_quality_is_same_and_custom_format_is_upgrade_and_upgrading_is_not_allowed()
|
||||
{
|
||||
_qualityProfile.UpgradeAllowed = false;
|
||||
|
||||
Subject.IsUpgradeAllowed(
|
||||
_qualityProfile,
|
||||
new QualityModel(Quality.DVD),
|
||||
new List<CustomFormat> { _customFormatOne },
|
||||
new QualityModel(Quality.DVD),
|
||||
new List<CustomFormat> { _customFormatTwo })
|
||||
.Should().BeFalse();
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void should_return_true_for_custom_format_upgrade_when_upgrading_is_allowed()
|
||||
{
|
||||
_qualityProfile.UpgradeAllowed = true;
|
||||
|
||||
Subject.IsUpgradeAllowed(
|
||||
_qualityProfile,
|
||||
new QualityModel(Quality.DVD),
|
||||
new List<CustomFormat> { _customFormatOne },
|
||||
new QualityModel(Quality.DVD),
|
||||
new List<CustomFormat> { _customFormatTwo })
|
||||
.Should().BeTrue();
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void should_return_true_for_same_custom_format_score_when_upgrading_is_not_allowed()
|
||||
{
|
||||
_qualityProfile.UpgradeAllowed = false;
|
||||
|
||||
Subject.IsUpgradeAllowed(
|
||||
_qualityProfile,
|
||||
new QualityModel(Quality.DVD),
|
||||
new List<CustomFormat> { _customFormatOne },
|
||||
new QualityModel(Quality.DVD),
|
||||
new List<CustomFormat> { _customFormatOne })
|
||||
.Should().BeTrue();
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void should_return_true_for_lower_custom_format_score_when_upgrading_is_allowed()
|
||||
{
|
||||
_qualityProfile.UpgradeAllowed = true;
|
||||
|
||||
Subject.IsUpgradeAllowed(
|
||||
_qualityProfile,
|
||||
new QualityModel(Quality.DVD),
|
||||
new List<CustomFormat> { _customFormatTwo },
|
||||
new QualityModel(Quality.DVD),
|
||||
new List<CustomFormat> { _customFormatOne })
|
||||
.Should().BeTrue();
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void should_return_true_for_lower_language_when_upgrading_is_not_allowed()
|
||||
{
|
||||
_qualityProfile.UpgradeAllowed = false;
|
||||
|
||||
Subject.IsUpgradeAllowed(
|
||||
_qualityProfile,
|
||||
new QualityModel(Quality.DVD),
|
||||
new List<CustomFormat> { _customFormatTwo },
|
||||
new QualityModel(Quality.DVD),
|
||||
new List<CustomFormat> { _customFormatOne })
|
||||
.Should().BeTrue();
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void should_return_true_for_quality_upgrade_when_upgrading_is_allowed()
|
||||
{
|
||||
_qualityProfile.UpgradeAllowed = true;
|
||||
|
||||
Subject.IsUpgradeAllowed(
|
||||
_qualityProfile,
|
||||
new QualityModel(Quality.DVD),
|
||||
new List<CustomFormat>(),
|
||||
new QualityModel(Quality.Bluray1080p),
|
||||
new List<CustomFormat>())
|
||||
.Should().BeTrue();
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void should_return_true_for_same_quality_when_upgrading_is_allowed()
|
||||
{
|
||||
_qualityProfile.UpgradeAllowed = true;
|
||||
|
||||
Subject.IsUpgradeAllowed(
|
||||
_qualityProfile,
|
||||
new QualityModel(Quality.DVD),
|
||||
new List<CustomFormat>(),
|
||||
new QualityModel(Quality.DVD),
|
||||
new List<CustomFormat>())
|
||||
.Should().BeTrue();
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void should_return_true_for_same_quality_when_upgrading_is_not_allowed()
|
||||
{
|
||||
_qualityProfile.UpgradeAllowed = false;
|
||||
|
||||
Subject.IsUpgradeAllowed(
|
||||
_qualityProfile,
|
||||
new QualityModel(Quality.DVD),
|
||||
new List<CustomFormat>(),
|
||||
new QualityModel(Quality.DVD),
|
||||
new List<CustomFormat>())
|
||||
.Should().BeTrue();
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void should_return_true_for_lower_quality_when_upgrading_is_allowed()
|
||||
{
|
||||
_qualityProfile.UpgradeAllowed = true;
|
||||
|
||||
Subject.IsUpgradeAllowed(
|
||||
_qualityProfile,
|
||||
new QualityModel(Quality.DVD),
|
||||
new List<CustomFormat>(),
|
||||
new QualityModel(Quality.SDTV),
|
||||
new List<CustomFormat>())
|
||||
.Should().BeTrue();
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void should_return_true_for_lower_quality_when_upgrading_is_not_allowed()
|
||||
{
|
||||
_qualityProfile.UpgradeAllowed = false;
|
||||
|
||||
Subject.IsUpgradeAllowed(
|
||||
_qualityProfile,
|
||||
new QualityModel(Quality.DVD),
|
||||
new List<CustomFormat>(),
|
||||
new QualityModel(Quality.SDTV),
|
||||
new List<CustomFormat>())
|
||||
.Should().BeTrue();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -32,7 +32,7 @@ namespace NzbDrone.Core.Test.DecisionEngineTests
|
||||
Mocker.Resolve<UpgradableSpecification>();
|
||||
_upgradeDisk = Mocker.Resolve<UpgradeDiskSpecification>();
|
||||
|
||||
CustomFormatsTestHelpers.GivenCustomFormats();
|
||||
CustomFormatsFixture.GivenCustomFormats();
|
||||
|
||||
_firstFile = new MovieFile { Quality = new QualityModel(Quality.Bluray1080p, new Revision(version: 2)), DateAdded = DateTime.Now };
|
||||
|
||||
@@ -40,7 +40,7 @@ namespace NzbDrone.Core.Test.DecisionEngineTests
|
||||
.With(c => c.Profile = new Profile
|
||||
{
|
||||
Cutoff = Quality.Bluray1080p.Id, Items = Qualities.QualityFixture.GetDefaultQualities(),
|
||||
FormatItems = CustomFormatsTestHelpers.GetSampleFormatItems(),
|
||||
FormatItems = CustomFormatsFixture.GetSampleFormatItems(),
|
||||
MinFormatScore = 0
|
||||
})
|
||||
.With(e => e.MovieFiles = new List<MovieFile> { _firstFile })
|
||||
|
||||
@@ -1,112 +0,0 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using FizzWare.NBuilder;
|
||||
using FluentAssertions;
|
||||
using NUnit.Framework;
|
||||
using NzbDrone.Core.Download.Aggregation.Aggregators;
|
||||
using NzbDrone.Core.Languages;
|
||||
using NzbDrone.Core.Movies;
|
||||
using NzbDrone.Core.Parser.Model;
|
||||
using NzbDrone.Core.Test.Framework;
|
||||
|
||||
namespace NzbDrone.Core.Test.Download.Aggregation.Aggregators
|
||||
{
|
||||
[TestFixture]
|
||||
public class AggregateLanguagesFixture : CoreTest<AggregateLanguages>
|
||||
{
|
||||
private RemoteMovie _remoteMovie;
|
||||
private Movie _movie;
|
||||
private string _simpleReleaseTitle = "Series.Title.S01E01.xyz-RlsGroup";
|
||||
|
||||
[SetUp]
|
||||
public void Setup()
|
||||
{
|
||||
_movie = Builder<Movie>.CreateNew()
|
||||
.With(m => m.MovieMetadata = new MovieMetadata
|
||||
{
|
||||
Title = "Some Movie",
|
||||
OriginalLanguage = Language.English
|
||||
})
|
||||
.Build();
|
||||
|
||||
_remoteMovie = Builder<RemoteMovie>.CreateNew()
|
||||
.With(l => l.ParsedMovieInfo = null)
|
||||
.With(l => l.Movie = _movie)
|
||||
.Build();
|
||||
}
|
||||
|
||||
private ParsedMovieInfo GetParsedMovieInfo(List<Language> languages, string releaseTitle, string releaseTokens = "")
|
||||
{
|
||||
return new ParsedMovieInfo
|
||||
{
|
||||
Languages = languages,
|
||||
ReleaseTitle = releaseTitle,
|
||||
SimpleReleaseTitle = releaseTokens
|
||||
};
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void should_return_existing_language_if_episode_title_does_not_have_language()
|
||||
{
|
||||
_remoteMovie.ParsedMovieInfo = GetParsedMovieInfo(new List<Language> { Language.Original }, _simpleReleaseTitle);
|
||||
|
||||
Subject.Aggregate(_remoteMovie).Languages.Should().Contain(_movie.MovieMetadata.Value.OriginalLanguage);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void should_return_parsed_language()
|
||||
{
|
||||
_remoteMovie.ParsedMovieInfo = GetParsedMovieInfo(new List<Language> { Language.French }, _simpleReleaseTitle);
|
||||
|
||||
Subject.Aggregate(_remoteMovie).Languages.Should().Equal(_remoteMovie.ParsedMovieInfo.Languages);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void should_exclude_language_that_is_part_of_episode_title_when_release_tokens_contains_episode_title()
|
||||
{
|
||||
var releaseTitle = "Series.Title.S01E01.Jimmy.The.Greek.xyz-RlsGroup";
|
||||
var releaseTokens = ".Jimmy.The.Greek.xyz-RlsGroup";
|
||||
|
||||
_remoteMovie.Movie.Title = "Jimmy The Greek";
|
||||
_remoteMovie.ParsedMovieInfo = GetParsedMovieInfo(new List<Language> { Language.Greek }, releaseTitle, releaseTokens);
|
||||
|
||||
Subject.Aggregate(_remoteMovie).Languages.Should().Equal(_movie.MovieMetadata.Value.OriginalLanguage);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void should_remove_parsed_language_that_is_part_of_episode_title_when_release_tokens_contains_episode_title()
|
||||
{
|
||||
var releaseTitle = "Series.Title.S01E01.Jimmy.The.Greek.French.xyz-RlsGroup";
|
||||
var releaseTokens = ".Jimmy.The.Greek.French.xyz-RlsGroup";
|
||||
|
||||
_remoteMovie.Movie.Title = "Jimmy The Greek";
|
||||
_remoteMovie.ParsedMovieInfo = GetParsedMovieInfo(new List<Language> { Language.Greek, Language.French }, releaseTitle, releaseTokens);
|
||||
|
||||
Subject.Aggregate(_remoteMovie).Languages.Should().Equal(Language.French);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void should_not_exclude_language_that_is_part_of_episode_title_when_release_tokens_does_not_contain_episode_title()
|
||||
{
|
||||
var releaseTitle = "Series.Title.S01E01.xyz-RlsGroup";
|
||||
var releaseTokens = ".xyz-RlsGroup";
|
||||
|
||||
_remoteMovie.Movie.Title = "Jimmy The Greek";
|
||||
_remoteMovie.ParsedMovieInfo = GetParsedMovieInfo(new List<Language> { Language.Greek }, releaseTitle, releaseTokens);
|
||||
|
||||
Subject.Aggregate(_remoteMovie).Languages.Should().Equal(Language.Greek);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void should_use_reparse_language_after_determining_languages_that_are_in_episode_titles()
|
||||
{
|
||||
var releaseTitle = "Series.Title.S01E01.Jimmy.The.Greek.Greek.xyz-RlsGroup";
|
||||
var releaseTokens = ".Jimmy.The.Greek.Greek.xyz-RlsGroup";
|
||||
|
||||
_remoteMovie.Movie.Title = "Jimmy The Greek";
|
||||
_remoteMovie.ParsedMovieInfo = GetParsedMovieInfo(new List<Language> { Language.Greek }, releaseTitle, releaseTokens);
|
||||
|
||||
Subject.Aggregate(_remoteMovie).Languages.Should().Equal(Language.Greek);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,367 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using FluentAssertions;
|
||||
using Moq;
|
||||
using NUnit.Framework;
|
||||
using NzbDrone.Common.Disk;
|
||||
using NzbDrone.Common.Http;
|
||||
using NzbDrone.Core.Download;
|
||||
using NzbDrone.Core.Download.Clients;
|
||||
using NzbDrone.Core.Download.Clients.FreeboxDownload;
|
||||
using NzbDrone.Core.Download.Clients.FreeboxDownload.Responses;
|
||||
using NzbDrone.Core.Movies;
|
||||
using NzbDrone.Core.Parser.Model;
|
||||
|
||||
namespace NzbDrone.Core.Test.Download.DownloadClientTests.FreeboxDownloadTests
|
||||
{
|
||||
[TestFixture]
|
||||
public class TorrentFreeboxDownloadFixture : DownloadClientFixtureBase<TorrentFreeboxDownload>
|
||||
{
|
||||
protected FreeboxDownloadSettings _settings;
|
||||
|
||||
protected FreeboxDownloadConfiguration _downloadConfiguration;
|
||||
|
||||
protected FreeboxDownloadTask _task;
|
||||
|
||||
protected string _defaultDestination = @"/some/path";
|
||||
protected string _encodedDefaultDestination = "L3NvbWUvcGF0aA==";
|
||||
protected string _category = "somecat";
|
||||
protected string _encodedDefaultDestinationAndCategory = "L3NvbWUvcGF0aC9zb21lY2F0";
|
||||
protected string _destinationDirectory = @"/path/to/media";
|
||||
protected string _encodedDestinationDirectory = "L3BhdGgvdG8vbWVkaWE=";
|
||||
protected OsPath _physicalPath = new OsPath("/mnt/sdb1/mydata");
|
||||
protected string _downloadURL => "magnet:?xt=urn:btih:5dee65101db281ac9c46344cd6b175cdcad53426&dn=download";
|
||||
|
||||
[SetUp]
|
||||
public void Setup()
|
||||
{
|
||||
Subject.Definition = new DownloadClientDefinition();
|
||||
|
||||
_settings = new FreeboxDownloadSettings()
|
||||
{
|
||||
Host = "127.0.0.1",
|
||||
Port = 443,
|
||||
ApiUrl = "/api/v1/",
|
||||
AppId = "someid",
|
||||
AppToken = "S0mEv3RY1oN9T0k3n"
|
||||
};
|
||||
|
||||
Subject.Definition.Settings = _settings;
|
||||
|
||||
_downloadConfiguration = new FreeboxDownloadConfiguration()
|
||||
{
|
||||
DownloadDirectory = _encodedDefaultDestination
|
||||
};
|
||||
|
||||
_task = new FreeboxDownloadTask()
|
||||
{
|
||||
Id = "id0",
|
||||
Name = "name",
|
||||
DownloadDirectory = "L3NvbWUvcGF0aA==",
|
||||
InfoHash = "HASH",
|
||||
QueuePosition = 1,
|
||||
Status = FreeboxDownloadTaskStatus.Unknown,
|
||||
Eta = 0,
|
||||
Error = "none",
|
||||
Type = FreeboxDownloadTaskType.Bt.ToString(),
|
||||
IoPriority = FreeboxDownloadTaskIoPriority.Normal.ToString(),
|
||||
StopRatio = 150,
|
||||
PieceLength = 125,
|
||||
CreatedTimestamp = 1665261599,
|
||||
Size = 1000,
|
||||
ReceivedPrct = 0,
|
||||
ReceivedBytes = 0,
|
||||
ReceivedRate = 0,
|
||||
TransmittedPrct = 0,
|
||||
TransmittedBytes = 0,
|
||||
TransmittedRate = 0,
|
||||
};
|
||||
|
||||
Mocker.GetMock<IHttpClient>()
|
||||
.Setup(s => s.Get(It.IsAny<HttpRequest>()))
|
||||
.Returns<HttpRequest>(r => new HttpResponse(r, new HttpHeader(), Array.Empty<byte>()));
|
||||
}
|
||||
|
||||
protected void GivenCategory()
|
||||
{
|
||||
_settings.Category = _category;
|
||||
}
|
||||
|
||||
protected void GivenDestinationDirectory()
|
||||
{
|
||||
_settings.DestinationDirectory = _destinationDirectory;
|
||||
}
|
||||
|
||||
protected virtual void GivenDownloadConfiguration()
|
||||
{
|
||||
Mocker.GetMock<IFreeboxDownloadProxy>()
|
||||
.Setup(s => s.GetDownloadConfiguration(It.IsAny<FreeboxDownloadSettings>()))
|
||||
.Returns(_downloadConfiguration);
|
||||
}
|
||||
|
||||
protected virtual void GivenTasks(List<FreeboxDownloadTask> torrents)
|
||||
{
|
||||
if (torrents == null)
|
||||
{
|
||||
torrents = new List<FreeboxDownloadTask>();
|
||||
}
|
||||
|
||||
Mocker.GetMock<IFreeboxDownloadProxy>()
|
||||
.Setup(s => s.GetTasks(It.IsAny<FreeboxDownloadSettings>()))
|
||||
.Returns(torrents);
|
||||
}
|
||||
|
||||
protected void PrepareClientToReturnQueuedItem()
|
||||
{
|
||||
_task.Status = FreeboxDownloadTaskStatus.Queued;
|
||||
|
||||
GivenTasks(new List<FreeboxDownloadTask>
|
||||
{
|
||||
_task
|
||||
});
|
||||
}
|
||||
|
||||
protected void GivenSuccessfulDownload()
|
||||
{
|
||||
Mocker.GetMock<IHttpClient>()
|
||||
.Setup(s => s.Get(It.IsAny<HttpRequest>()))
|
||||
.Returns<HttpRequest>(r => new HttpResponse(r, new HttpHeader(), new byte[1000]));
|
||||
|
||||
Mocker.GetMock<IFreeboxDownloadProxy>()
|
||||
.Setup(s => s.AddTaskFromUrl(It.IsAny<string>(), It.IsAny<string>(), It.IsAny<bool>(), It.IsAny<bool>(), It.IsAny<double?>(), It.IsAny<FreeboxDownloadSettings>()))
|
||||
.Callback(PrepareClientToReturnQueuedItem);
|
||||
|
||||
Mocker.GetMock<IFreeboxDownloadProxy>()
|
||||
.Setup(s => s.AddTaskFromFile(It.IsAny<string>(), It.IsAny<byte[]>(), It.IsAny<string>(), It.IsAny<bool>(), It.IsAny<bool>(), It.IsAny<double?>(), It.IsAny<FreeboxDownloadSettings>()))
|
||||
.Callback(PrepareClientToReturnQueuedItem);
|
||||
}
|
||||
|
||||
protected override RemoteMovie CreateRemoteMovie()
|
||||
{
|
||||
var movie = base.CreateRemoteMovie();
|
||||
|
||||
movie.Release.DownloadUrl = _downloadURL;
|
||||
|
||||
return movie;
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Download_with_DestinationDirectory_should_force_directory()
|
||||
{
|
||||
GivenDestinationDirectory();
|
||||
GivenSuccessfulDownload();
|
||||
|
||||
var remoteMovie = CreateRemoteMovie();
|
||||
|
||||
Subject.Download(remoteMovie);
|
||||
|
||||
Mocker.GetMock<IFreeboxDownloadProxy>()
|
||||
.Verify(v => v.AddTaskFromUrl(It.IsAny<string>(), _encodedDestinationDirectory, It.IsAny<bool>(), It.IsAny<bool>(), It.IsAny<double?>(), It.IsAny<FreeboxDownloadSettings>()), Times.Once());
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Download_with_Category_should_force_directory()
|
||||
{
|
||||
GivenDownloadConfiguration();
|
||||
GivenCategory();
|
||||
GivenSuccessfulDownload();
|
||||
|
||||
var remoteMovie = CreateRemoteMovie();
|
||||
|
||||
Subject.Download(remoteMovie);
|
||||
|
||||
Mocker.GetMock<IFreeboxDownloadProxy>()
|
||||
.Verify(v => v.AddTaskFromUrl(It.IsAny<string>(), _encodedDefaultDestinationAndCategory, It.IsAny<bool>(), It.IsAny<bool>(), It.IsAny<double?>(), It.IsAny<FreeboxDownloadSettings>()), Times.Once());
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Download_without_DestinationDirectory_and_Category_should_use_default()
|
||||
{
|
||||
GivenDownloadConfiguration();
|
||||
GivenSuccessfulDownload();
|
||||
|
||||
var remoteMovie = CreateRemoteMovie();
|
||||
|
||||
Subject.Download(remoteMovie);
|
||||
|
||||
Mocker.GetMock<IFreeboxDownloadProxy>()
|
||||
.Verify(v => v.AddTaskFromUrl(It.IsAny<string>(), _encodedDefaultDestination, It.IsAny<bool>(), It.IsAny<bool>(), It.IsAny<double?>(), It.IsAny<FreeboxDownloadSettings>()), Times.Once());
|
||||
}
|
||||
|
||||
[TestCase(false, false)]
|
||||
[TestCase(true, true)]
|
||||
public void Download_should_pause_torrent_as_expected(bool addPausedSetting, bool toBePausedFlag)
|
||||
{
|
||||
_settings.AddPaused = addPausedSetting;
|
||||
|
||||
GivenDownloadConfiguration();
|
||||
GivenSuccessfulDownload();
|
||||
|
||||
var remoteMovie = CreateRemoteMovie();
|
||||
|
||||
Subject.Download(remoteMovie);
|
||||
|
||||
Mocker.GetMock<IFreeboxDownloadProxy>()
|
||||
.Verify(v => v.AddTaskFromUrl(It.IsAny<string>(), It.IsAny<string>(), toBePausedFlag, It.IsAny<bool>(), It.IsAny<double?>(), It.IsAny<FreeboxDownloadSettings>()), Times.Once());
|
||||
}
|
||||
|
||||
[TestCase(0, (int)FreeboxDownloadPriority.First, (int)FreeboxDownloadPriority.First, true)]
|
||||
[TestCase(0, (int)FreeboxDownloadPriority.Last, (int)FreeboxDownloadPriority.First, true)]
|
||||
[TestCase(0, (int)FreeboxDownloadPriority.First, (int)FreeboxDownloadPriority.Last, false)]
|
||||
[TestCase(0, (int)FreeboxDownloadPriority.Last, (int)FreeboxDownloadPriority.Last, false)]
|
||||
[TestCase(22, (int)FreeboxDownloadPriority.First, (int)FreeboxDownloadPriority.First, true)]
|
||||
[TestCase(22, (int)FreeboxDownloadPriority.Last, (int)FreeboxDownloadPriority.First, false)]
|
||||
[TestCase(22, (int)FreeboxDownloadPriority.First, (int)FreeboxDownloadPriority.Last, true)]
|
||||
[TestCase(22, (int)FreeboxDownloadPriority.Last, (int)FreeboxDownloadPriority.Last, false)]
|
||||
public void Download_should_queue_torrent_first_as_expected(int ageDay, int olderPriority, int recentPriority, bool toBeQueuedFirstFlag)
|
||||
{
|
||||
_settings.OlderPriority = olderPriority;
|
||||
_settings.RecentPriority = recentPriority;
|
||||
|
||||
GivenDownloadConfiguration();
|
||||
GivenSuccessfulDownload();
|
||||
|
||||
var remoteMovie = CreateRemoteMovie();
|
||||
|
||||
remoteMovie.Movie.MovieMetadata.Value.PhysicalRelease = DateTime.UtcNow.AddDays(-ageDay);
|
||||
|
||||
Subject.Download(remoteMovie);
|
||||
|
||||
Mocker.GetMock<IFreeboxDownloadProxy>()
|
||||
.Verify(v => v.AddTaskFromUrl(It.IsAny<string>(), It.IsAny<string>(), It.IsAny<bool>(), toBeQueuedFirstFlag, It.IsAny<double?>(), It.IsAny<FreeboxDownloadSettings>()), Times.Once());
|
||||
}
|
||||
|
||||
[TestCase(0, 0)]
|
||||
[TestCase(1.5, 150)]
|
||||
public void Download_should_define_seed_ratio_as_expected(double? providerSeedRatio, double? expectedSeedRatio)
|
||||
{
|
||||
GivenDownloadConfiguration();
|
||||
GivenSuccessfulDownload();
|
||||
|
||||
var remoteMovie = CreateRemoteMovie();
|
||||
|
||||
remoteMovie.SeedConfiguration = new TorrentSeedConfiguration();
|
||||
remoteMovie.SeedConfiguration.Ratio = providerSeedRatio;
|
||||
|
||||
Subject.Download(remoteMovie);
|
||||
|
||||
Mocker.GetMock<IFreeboxDownloadProxy>()
|
||||
.Verify(v => v.AddTaskFromUrl(It.IsAny<string>(), It.IsAny<string>(), It.IsAny<bool>(), It.IsAny<bool>(), expectedSeedRatio, It.IsAny<FreeboxDownloadSettings>()), Times.Once());
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void GetItems_should_return_empty_list_if_no_tasks_available()
|
||||
{
|
||||
GivenTasks(new List<FreeboxDownloadTask>());
|
||||
|
||||
Subject.GetItems().Should().BeEmpty();
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void GetItems_should_return_ignore_tasks_of_unknown_type()
|
||||
{
|
||||
_task.Status = FreeboxDownloadTaskStatus.Done;
|
||||
_task.Type = "toto";
|
||||
|
||||
GivenTasks(new List<FreeboxDownloadTask> { _task });
|
||||
|
||||
Subject.GetItems().Should().BeEmpty();
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void GetItems_when_destinationdirectory_is_set_should_ignore_downloads_in_wrong_folder()
|
||||
{
|
||||
_settings.DestinationDirectory = @"/some/path/that/will/not/match";
|
||||
|
||||
_task.Status = FreeboxDownloadTaskStatus.Done;
|
||||
|
||||
GivenTasks(new List<FreeboxDownloadTask> { _task });
|
||||
|
||||
Subject.GetItems().Should().BeEmpty();
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void GetItems_when_category_is_set_should_ignore_downloads_in_wrong_folder()
|
||||
{
|
||||
_settings.Category = "somecategory";
|
||||
|
||||
_task.Status = FreeboxDownloadTaskStatus.Done;
|
||||
|
||||
GivenTasks(new List<FreeboxDownloadTask> { _task });
|
||||
|
||||
Subject.GetItems().Should().BeEmpty();
|
||||
}
|
||||
|
||||
[TestCase(FreeboxDownloadTaskStatus.Downloading, false, false)]
|
||||
[TestCase(FreeboxDownloadTaskStatus.Done, true, true)]
|
||||
[TestCase(FreeboxDownloadTaskStatus.Seeding, false, false)]
|
||||
[TestCase(FreeboxDownloadTaskStatus.Stopped, false, false)]
|
||||
public void GetItems_should_return_canBeMoved_and_canBeDeleted_as_expected(FreeboxDownloadTaskStatus apiStatus, bool canMoveFilesExpected, bool canBeRemovedExpected)
|
||||
{
|
||||
_task.Status = apiStatus;
|
||||
|
||||
GivenTasks(new List<FreeboxDownloadTask>() { _task });
|
||||
|
||||
var items = Subject.GetItems();
|
||||
|
||||
items.Should().HaveCount(1);
|
||||
items.First().CanBeRemoved.Should().Be(canBeRemovedExpected);
|
||||
items.First().CanMoveFiles.Should().Be(canMoveFilesExpected);
|
||||
}
|
||||
|
||||
[TestCase(FreeboxDownloadTaskStatus.Stopped, DownloadItemStatus.Paused)]
|
||||
[TestCase(FreeboxDownloadTaskStatus.Stopping, DownloadItemStatus.Paused)]
|
||||
[TestCase(FreeboxDownloadTaskStatus.Queued, DownloadItemStatus.Queued)]
|
||||
[TestCase(FreeboxDownloadTaskStatus.Starting, DownloadItemStatus.Downloading)]
|
||||
[TestCase(FreeboxDownloadTaskStatus.Downloading, DownloadItemStatus.Downloading)]
|
||||
[TestCase(FreeboxDownloadTaskStatus.Retry, DownloadItemStatus.Downloading)]
|
||||
[TestCase(FreeboxDownloadTaskStatus.Checking, DownloadItemStatus.Downloading)]
|
||||
[TestCase(FreeboxDownloadTaskStatus.Error, DownloadItemStatus.Warning)]
|
||||
[TestCase(FreeboxDownloadTaskStatus.Seeding, DownloadItemStatus.Completed)]
|
||||
[TestCase(FreeboxDownloadTaskStatus.Done, DownloadItemStatus.Completed)]
|
||||
[TestCase(FreeboxDownloadTaskStatus.Unknown, DownloadItemStatus.Downloading)]
|
||||
public void GetItems_should_return_item_as_downloadItemStatus(FreeboxDownloadTaskStatus apiStatus, DownloadItemStatus expectedItemStatus)
|
||||
{
|
||||
_task.Status = apiStatus;
|
||||
|
||||
GivenTasks(new List<FreeboxDownloadTask>() { _task });
|
||||
|
||||
var items = Subject.GetItems();
|
||||
|
||||
items.Should().HaveCount(1);
|
||||
items.First().Status.Should().Be(expectedItemStatus);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void GetItems_should_return_decoded_destination_directory()
|
||||
{
|
||||
var decodedDownloadDirectory = "/that/the/path";
|
||||
|
||||
_task.Status = FreeboxDownloadTaskStatus.Done;
|
||||
_task.DownloadDirectory = "L3RoYXQvdGhlL3BhdGg=";
|
||||
|
||||
GivenTasks(new List<FreeboxDownloadTask> { _task });
|
||||
|
||||
var items = Subject.GetItems();
|
||||
|
||||
items.Should().HaveCount(1);
|
||||
items.First().OutputPath.Should().Be(decodedDownloadDirectory);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void GetItems_should_return_message_if_tasks_in_error()
|
||||
{
|
||||
_task.Status = FreeboxDownloadTaskStatus.Error;
|
||||
_task.Error = "internal";
|
||||
|
||||
GivenTasks(new List<FreeboxDownloadTask> { _task });
|
||||
|
||||
var items = Subject.GetItems();
|
||||
|
||||
items.Should().HaveCount(1);
|
||||
items.First().Message.Should().Be("Internal error.");
|
||||
items.First().Status.Should().Be(DownloadItemStatus.Warning);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,4 +1,3 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using FluentAssertions;
|
||||
@@ -276,7 +275,7 @@ namespace NzbDrone.Core.Test.Download.DownloadClientTests.TransmissionTests
|
||||
|
||||
[TestCase(-1)] // Infinite/Unknown
|
||||
[TestCase(-2)] // Magnet Downloading
|
||||
public void should_ignore_negative_eta(long eta)
|
||||
public void should_ignore_negative_eta(int eta)
|
||||
{
|
||||
_completed.Eta = eta;
|
||||
|
||||
@@ -285,26 +284,6 @@ namespace NzbDrone.Core.Test.Download.DownloadClientTests.TransmissionTests
|
||||
item.RemainingTime.Should().NotHaveValue();
|
||||
}
|
||||
|
||||
[TestCase(2147483648)] // 2038-01-19T03:14:08Z > int.MaxValue as unix timestamp can be either an int or a long
|
||||
public void should_support_long_values_for_eta_in_seconds(long eta)
|
||||
{
|
||||
_downloading.Eta = eta;
|
||||
|
||||
PrepareClientToReturnDownloadingItem();
|
||||
var item = Subject.GetItems().Single();
|
||||
item.RemainingTime.Should().Be(TimeSpan.FromSeconds(eta));
|
||||
}
|
||||
|
||||
[TestCase(2147483648000)] // works with milliseconds format too
|
||||
public void should_support_long_values_for_eta_in_milliseconds(long eta)
|
||||
{
|
||||
_downloading.Eta = eta;
|
||||
|
||||
PrepareClientToReturnDownloadingItem();
|
||||
var item = Subject.GetItems().Single();
|
||||
item.RemainingTime.Should().Be(TimeSpan.FromMilliseconds(eta));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void should_not_be_removable_and_should_not_allow_move_files_if_max_ratio_reached_and_not_stopped()
|
||||
{
|
||||
|
||||
@@ -271,7 +271,7 @@ namespace NzbDrone.Core.Test.Download.DownloadClientTests.VuzeTests
|
||||
|
||||
[TestCase(-1)] // Infinite/Unknown
|
||||
[TestCase(-2)] // Magnet Downloading
|
||||
public void should_ignore_negative_eta(long eta)
|
||||
public void should_ignore_negative_eta(int eta)
|
||||
{
|
||||
_completed.Eta = eta;
|
||||
|
||||
|
||||
@@ -27,7 +27,7 @@ namespace NzbDrone.Core.Test.Download
|
||||
_downloadClients = new List<IDownloadClient>();
|
||||
|
||||
Mocker.GetMock<IProvideDownloadClient>()
|
||||
.Setup(v => v.GetDownloadClients(It.IsAny<bool>()))
|
||||
.Setup(v => v.GetDownloadClients())
|
||||
.Returns(_downloadClients);
|
||||
|
||||
Mocker.GetMock<IProvideDownloadClient>()
|
||||
|
||||
@@ -89,7 +89,6 @@ namespace NzbDrone.Core.Test.Download.Pending.PendingReleaseServiceTests
|
||||
.With(h => h.Title = title)
|
||||
.With(h => h.Release = release)
|
||||
.With(h => h.Reason = reason)
|
||||
.With(h => h.ParsedMovieInfo = _parsedMovieInfo)
|
||||
.Build();
|
||||
|
||||
_heldReleases.AddRange(heldReleases);
|
||||
|
||||
@@ -52,9 +52,7 @@ namespace NzbDrone.Core.Test.Download.Pending.PendingReleaseServiceTests
|
||||
_pending.Add(new PendingRelease
|
||||
{
|
||||
Id = id,
|
||||
Title = "Movie.Title.2020.720p-Radarr",
|
||||
ParsedMovieInfo = new ParsedMovieInfo { MovieTitles = new List<string> { title }, Year = year },
|
||||
Release = Builder<ReleaseInfo>.CreateNew().Build(),
|
||||
MovieId = _movie.Id
|
||||
});
|
||||
}
|
||||
|
||||
@@ -93,7 +93,6 @@ namespace NzbDrone.Core.Test.Download.Pending.PendingReleaseServiceTests
|
||||
.With(h => h.MovieId = _movie.Id)
|
||||
.With(h => h.Title = title)
|
||||
.With(h => h.Release = release)
|
||||
.With(h => h.ParsedMovieInfo = _parsedMovieInfo)
|
||||
.Build();
|
||||
|
||||
Mocker.GetMock<IPendingReleaseRepository>()
|
||||
|
||||
@@ -62,7 +62,7 @@ namespace NzbDrone.Core.Test.Extras.Others
|
||||
|
||||
var results = Subject.ImportFiles(_localMovie, _movieFile, files, true).ToList();
|
||||
|
||||
results.Count.Should().Be(1);
|
||||
results.Count().Should().Be(1);
|
||||
|
||||
results[0].RelativePath.AsOsAgnostic().PathEquals(expectedOutputPath.AsOsAgnostic()).Should().Be(true);
|
||||
}
|
||||
@@ -78,7 +78,7 @@ namespace NzbDrone.Core.Test.Extras.Others
|
||||
|
||||
var results = Subject.ImportFiles(_localMovie, _movieFile, files, true).ToList();
|
||||
|
||||
results.Count.Should().Be(1);
|
||||
results.Count().Should().Be(1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -67,7 +67,7 @@ namespace NzbDrone.Core.Test.Extras.Subtitles
|
||||
|
||||
var results = Subject.ImportFiles(_localMovie, _movieFile, files, true).ToList();
|
||||
|
||||
results.Count.Should().Be(0);
|
||||
results.Count().Should().Be(0);
|
||||
}
|
||||
|
||||
[Test]
|
||||
@@ -84,7 +84,7 @@ namespace NzbDrone.Core.Test.Extras.Subtitles
|
||||
|
||||
var results = Subject.ImportFiles(_localMovie, _movieFile, files, true).ToList();
|
||||
|
||||
results.Count.Should().Be(1);
|
||||
results.Count().Should().Be(1);
|
||||
|
||||
results[0].RelativePath.AsOsAgnostic().PathEquals(expectedOutputPath.AsOsAgnostic()).Should().Be(true);
|
||||
}
|
||||
@@ -110,7 +110,7 @@ namespace NzbDrone.Core.Test.Extras.Subtitles
|
||||
|
||||
var results = Subject.ImportFiles(_localMovie, _movieFile, files, true).ToList();
|
||||
|
||||
results.Count.Should().Be(expectedOutputs.Length);
|
||||
results.Count().Should().Be(expectedOutputs.Length);
|
||||
|
||||
for (int i = 0; i < expectedOutputs.Length; i++)
|
||||
{
|
||||
@@ -139,7 +139,7 @@ namespace NzbDrone.Core.Test.Extras.Subtitles
|
||||
|
||||
var results = Subject.ImportFiles(_localMovie, _movieFile, files, true).ToList();
|
||||
|
||||
results.Count.Should().Be(expectedOutputs.Length);
|
||||
results.Count().Should().Be(expectedOutputs.Length);
|
||||
|
||||
for (int i = 0; i < expectedOutputs.Length; i++)
|
||||
{
|
||||
@@ -169,7 +169,7 @@ namespace NzbDrone.Core.Test.Extras.Subtitles
|
||||
|
||||
var results = Subject.ImportFiles(_localMovie, _movieFile, new List<string> { subtitleFile }, true).ToList();
|
||||
|
||||
results.Count.Should().Be(1);
|
||||
results.Count().Should().Be(1);
|
||||
|
||||
results[0].RelativePath.AsOsAgnostic().PathEquals(expectedOutputPath.AsOsAgnostic()).Should().Be(true);
|
||||
|
||||
|
||||
1211
src/NzbDrone.Core.Test/Files/Indexers/Omgwtfnzbs/Omgwtfnzbs.xml
Normal file
1211
src/NzbDrone.Core.Test/Files/Indexers/Omgwtfnzbs/Omgwtfnzbs.xml
Normal file
File diff suppressed because it is too large
Load Diff
@@ -24,7 +24,7 @@ namespace NzbDrone.Core.Test.HealthCheck.Checks
|
||||
public void should_return_warning_when_download_client_has_not_been_configured()
|
||||
{
|
||||
Mocker.GetMock<IProvideDownloadClient>()
|
||||
.Setup(s => s.GetDownloadClients(It.IsAny<bool>()))
|
||||
.Setup(s => s.GetDownloadClients())
|
||||
.Returns(Array.Empty<IDownloadClient>());
|
||||
|
||||
Subject.Check().ShouldBeWarning();
|
||||
@@ -40,7 +40,7 @@ namespace NzbDrone.Core.Test.HealthCheck.Checks
|
||||
.Throws<Exception>();
|
||||
|
||||
Mocker.GetMock<IProvideDownloadClient>()
|
||||
.Setup(s => s.GetDownloadClients(It.IsAny<bool>()))
|
||||
.Setup(s => s.GetDownloadClients())
|
||||
.Returns(new IDownloadClient[] { downloadClient.Object });
|
||||
|
||||
Subject.Check().ShouldBeError();
|
||||
@@ -55,7 +55,7 @@ namespace NzbDrone.Core.Test.HealthCheck.Checks
|
||||
.Returns(new List<DownloadClientItem>());
|
||||
|
||||
Mocker.GetMock<IProvideDownloadClient>()
|
||||
.Setup(s => s.GetDownloadClients(It.IsAny<bool>()))
|
||||
.Setup(s => s.GetDownloadClients())
|
||||
.Returns(new IDownloadClient[] { downloadClient.Object });
|
||||
|
||||
Subject.Check().ShouldBeOk();
|
||||
|
||||
@@ -49,7 +49,7 @@ namespace NzbDrone.Core.Test.HealthCheck.Checks
|
||||
.Returns(_clientStatus);
|
||||
|
||||
Mocker.GetMock<IProvideDownloadClient>()
|
||||
.Setup(s => s.GetDownloadClients(It.IsAny<bool>()))
|
||||
.Setup(s => s.GetDownloadClients())
|
||||
.Returns(new IDownloadClient[] { _downloadClient.Object });
|
||||
|
||||
Mocker.GetMock<IDiskProvider>()
|
||||
|
||||
@@ -1,80 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Moq;
|
||||
using NUnit.Framework;
|
||||
using NzbDrone.Common.Disk;
|
||||
using NzbDrone.Core.Download;
|
||||
using NzbDrone.Core.Download.Clients;
|
||||
using NzbDrone.Core.HealthCheck.Checks;
|
||||
using NzbDrone.Core.Localization;
|
||||
using NzbDrone.Core.RootFolders;
|
||||
using NzbDrone.Core.Test.Framework;
|
||||
using NzbDrone.Test.Common;
|
||||
|
||||
namespace NzbDrone.Core.Test.HealthCheck.Checks
|
||||
{
|
||||
[TestFixture]
|
||||
public class DownloadClientFolderCheckFixture : CoreTest<DownloadClientSortingCheck>
|
||||
{
|
||||
private DownloadClientInfo _clientStatus;
|
||||
private Mock<IDownloadClient> _downloadClient;
|
||||
|
||||
private static Exception[] DownloadClientExceptions =
|
||||
{
|
||||
new DownloadClientUnavailableException("error"),
|
||||
new DownloadClientAuthenticationException("error"),
|
||||
new DownloadClientException("error")
|
||||
};
|
||||
|
||||
[SetUp]
|
||||
public void Setup()
|
||||
{
|
||||
Mocker.GetMock<ILocalizationService>()
|
||||
.Setup(s => s.GetLocalizedString(It.IsAny<string>()))
|
||||
.Returns("Some Warning Message");
|
||||
|
||||
_clientStatus = new DownloadClientInfo
|
||||
{
|
||||
IsLocalhost = true,
|
||||
SortingMode = null
|
||||
};
|
||||
|
||||
_downloadClient = Mocker.GetMock<IDownloadClient>();
|
||||
_downloadClient.Setup(s => s.Definition)
|
||||
.Returns(new DownloadClientDefinition { Name = "Test" });
|
||||
|
||||
_downloadClient.Setup(s => s.GetStatus())
|
||||
.Returns(_clientStatus);
|
||||
|
||||
Mocker.GetMock<IProvideDownloadClient>()
|
||||
.Setup(s => s.GetDownloadClients(It.IsAny<bool>()))
|
||||
.Returns(new IDownloadClient[] { _downloadClient.Object });
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void should_return_ok_if_sorting_is_not_enabled()
|
||||
{
|
||||
Subject.Check().ShouldBeOk();
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void should_return_warning_if_sorting_is_enabled()
|
||||
{
|
||||
_clientStatus.SortingMode = "TV";
|
||||
|
||||
Subject.Check().ShouldBeWarning();
|
||||
}
|
||||
|
||||
[Test]
|
||||
[TestCaseSource("DownloadClientExceptions")]
|
||||
public void should_return_ok_if_client_throws_downloadclientexception(Exception ex)
|
||||
{
|
||||
_downloadClient.Setup(s => s.GetStatus())
|
||||
.Throws(ex);
|
||||
|
||||
Subject.Check().ShouldBeOk();
|
||||
|
||||
ExceptionVerification.ExpectedErrors(0);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -63,7 +63,7 @@ namespace NzbDrone.Core.Test.HealthCheck.Checks
|
||||
.Returns(_clientStatus);
|
||||
|
||||
Mocker.GetMock<IProvideDownloadClient>()
|
||||
.Setup(s => s.GetDownloadClients(It.IsAny<bool>()))
|
||||
.Setup(s => s.GetDownloadClients())
|
||||
.Returns(new IDownloadClient[] { _downloadClient.Object });
|
||||
|
||||
Mocker.GetMock<IConfigService>()
|
||||
|
||||
@@ -1,133 +0,0 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using FizzWare.NBuilder;
|
||||
using FluentAssertions;
|
||||
using NUnit.Framework;
|
||||
using NzbDrone.Core.CustomFormats;
|
||||
using NzbDrone.Core.Datastore;
|
||||
using NzbDrone.Core.Housekeeping.Housekeepers;
|
||||
using NzbDrone.Core.Messaging.Events;
|
||||
using NzbDrone.Core.Profiles;
|
||||
using NzbDrone.Core.Test.Framework;
|
||||
|
||||
namespace NzbDrone.Core.Test.Housekeeping.Housekeepers
|
||||
{
|
||||
[TestFixture]
|
||||
public class CleanupQualityProfileFormatItemsFixture : DbTest<CleanupQualityProfileFormatItems, Profile>
|
||||
{
|
||||
[SetUp]
|
||||
public void Setup()
|
||||
{
|
||||
Mocker.SetConstant<IQualityProfileFormatItemsCleanupRepository>(
|
||||
new QualityProfileFormatItemsCleanupRepository(Mocker.Resolve<IMainDatabase>(), Mocker.Resolve<IEventAggregator>()));
|
||||
|
||||
Mocker.SetConstant<ICustomFormatRepository>(
|
||||
new CustomFormatRepository(Mocker.Resolve<IMainDatabase>(), Mocker.Resolve<IEventAggregator>()));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void should_remove_orphaned_custom_formats()
|
||||
{
|
||||
var qualityProfile = Builder<Profile>.CreateNew()
|
||||
.With(h => h.Items = Qualities.QualityFixture.GetDefaultQualities())
|
||||
.With(h => h.MinFormatScore = 50)
|
||||
.With(h => h.CutoffFormatScore = 100)
|
||||
.With(h => h.FormatItems = new List<ProfileFormatItem>
|
||||
{
|
||||
Builder<ProfileFormatItem>.CreateNew()
|
||||
.With(c => c.Format = new CustomFormat("My Custom Format") { Id = 0 })
|
||||
.Build()
|
||||
})
|
||||
.BuildNew();
|
||||
|
||||
Db.Insert(qualityProfile);
|
||||
Subject.Clean();
|
||||
|
||||
var result = AllStoredModels;
|
||||
|
||||
result.Should().HaveCount(1);
|
||||
result.First().FormatItems.Should().BeEmpty();
|
||||
result.First().MinFormatScore.Should().Be(0);
|
||||
result.First().CutoffFormatScore.Should().Be(0);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void should_not_remove_unorphaned_custom_formats()
|
||||
{
|
||||
var minFormatScore = 50;
|
||||
var cutoffFormatScore = 100;
|
||||
|
||||
var customFormat = Builder<CustomFormat>.CreateNew()
|
||||
.With(h => h.Specifications = new List<ICustomFormatSpecification>())
|
||||
.BuildNew();
|
||||
|
||||
Db.Insert(customFormat);
|
||||
|
||||
var qualityProfile = Builder<Profile>.CreateNew()
|
||||
.With(h => h.Items = Qualities.QualityFixture.GetDefaultQualities())
|
||||
.With(h => h.MinFormatScore = minFormatScore)
|
||||
.With(h => h.CutoffFormatScore = cutoffFormatScore)
|
||||
.With(h => h.FormatItems = new List<ProfileFormatItem>
|
||||
{
|
||||
Builder<ProfileFormatItem>.CreateNew()
|
||||
.With(c => c.Format = customFormat)
|
||||
.Build()
|
||||
})
|
||||
.BuildNew();
|
||||
|
||||
Db.Insert(qualityProfile);
|
||||
|
||||
Subject.Clean();
|
||||
var result = AllStoredModels;
|
||||
|
||||
result.Should().HaveCount(1);
|
||||
result.First().FormatItems.Should().HaveCount(1);
|
||||
result.First().MinFormatScore.Should().Be(minFormatScore);
|
||||
result.First().CutoffFormatScore.Should().Be(cutoffFormatScore);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void should_add_missing_custom_formats()
|
||||
{
|
||||
var minFormatScore = 50;
|
||||
var cutoffFormatScore = 100;
|
||||
|
||||
var customFormat1 = Builder<CustomFormat>.CreateNew()
|
||||
.With(h => h.Id = 1)
|
||||
.With(h => h.Name = "Custom Format 1")
|
||||
.With(h => h.Specifications = new List<ICustomFormatSpecification>())
|
||||
.BuildNew();
|
||||
|
||||
var customFormat2 = Builder<CustomFormat>.CreateNew()
|
||||
.With(h => h.Id = 2)
|
||||
.With(h => h.Name = "Custom Format 2")
|
||||
.With(h => h.Specifications = new List<ICustomFormatSpecification>())
|
||||
.BuildNew();
|
||||
|
||||
Db.Insert(customFormat1);
|
||||
Db.Insert(customFormat2);
|
||||
|
||||
var qualityProfile = Builder<Profile>.CreateNew()
|
||||
.With(h => h.Items = Qualities.QualityFixture.GetDefaultQualities())
|
||||
.With(h => h.MinFormatScore = minFormatScore)
|
||||
.With(h => h.CutoffFormatScore = cutoffFormatScore)
|
||||
.With(h => h.FormatItems = new List<ProfileFormatItem>
|
||||
{
|
||||
Builder<ProfileFormatItem>.CreateNew()
|
||||
.With(c => c.Format = customFormat1)
|
||||
.Build()
|
||||
})
|
||||
.BuildNew();
|
||||
|
||||
Db.Insert(qualityProfile);
|
||||
|
||||
Subject.Clean();
|
||||
var result = AllStoredModels;
|
||||
|
||||
result.Should().HaveCount(1);
|
||||
result.First().FormatItems.Should().HaveCount(2);
|
||||
result.First().MinFormatScore.Should().Be(minFormatScore);
|
||||
result.First().CutoffFormatScore.Should().Be(cutoffFormatScore);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,10 +1,10 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.Generic;
|
||||
using FizzWare.NBuilder;
|
||||
using FluentAssertions;
|
||||
using NUnit.Framework;
|
||||
using NzbDrone.Core.Indexers;
|
||||
using NzbDrone.Core.Indexers.FileList;
|
||||
using NzbDrone.Core.Indexers.Newznab;
|
||||
using NzbDrone.Core.Indexers.Omgwtfnzbs;
|
||||
using NzbDrone.Core.Lifecycle;
|
||||
using NzbDrone.Core.Test.Framework;
|
||||
|
||||
@@ -20,7 +20,7 @@ namespace NzbDrone.Core.Test.IndexerTests
|
||||
_indexers = new List<IIndexer>();
|
||||
|
||||
_indexers.Add(Mocker.Resolve<Newznab>());
|
||||
_indexers.Add(Mocker.Resolve<FileList>());
|
||||
_indexers.Add(Mocker.Resolve<Omgwtfnzbs>());
|
||||
|
||||
Mocker.SetConstant<IEnumerable<IIndexer>>(_indexers);
|
||||
}
|
||||
|
||||
@@ -62,21 +62,13 @@ namespace NzbDrone.Core.Test.IndexerTests.NewznabTests
|
||||
releaseInfo.Size.Should().Be(1183105773);
|
||||
}
|
||||
|
||||
public void should_use_best_pagesize_reported_by_caps()
|
||||
[Test]
|
||||
public void should_use_pagesize_reported_by_caps()
|
||||
{
|
||||
_caps.MaxPageSize = 30;
|
||||
_caps.DefaultPageSize = 25;
|
||||
|
||||
Subject.PageSize.Should().Be(30);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void should_not_use_pagesize_over_100_even_if_reported_in_caps()
|
||||
{
|
||||
_caps.MaxPageSize = 250;
|
||||
_caps.DefaultPageSize = 25;
|
||||
|
||||
Subject.PageSize.Should().Be(100);
|
||||
Subject.PageSize.Should().Be(25);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,56 @@
|
||||
using System;
|
||||
using System.Linq;
|
||||
using System.Net.Http;
|
||||
using FluentAssertions;
|
||||
using Moq;
|
||||
using NUnit.Framework;
|
||||
using NzbDrone.Common.Http;
|
||||
using NzbDrone.Core.Indexers;
|
||||
using NzbDrone.Core.Indexers.Omgwtfnzbs;
|
||||
using NzbDrone.Core.Test.Framework;
|
||||
|
||||
namespace NzbDrone.Core.Test.IndexerTests.OmgwtfnzbsTests
|
||||
{
|
||||
[TestFixture]
|
||||
public class OmgwtfnzbsFixture : CoreTest<Omgwtfnzbs>
|
||||
{
|
||||
[SetUp]
|
||||
public void Setup()
|
||||
{
|
||||
Subject.Definition = new IndexerDefinition()
|
||||
{
|
||||
Name = "Omgwtfnzbs",
|
||||
Settings = new OmgwtfnzbsSettings()
|
||||
{
|
||||
ApiKey = "xxx",
|
||||
Username = "me@my.domain"
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void should_parse_recent_feed_from_omgwtfnzbs()
|
||||
{
|
||||
var recentFeed = ReadAllText(@"Files/Indexers/Omgwtfnzbs/Omgwtfnzbs.xml");
|
||||
|
||||
Mocker.GetMock<IHttpClient>()
|
||||
.Setup(o => o.Execute(It.Is<HttpRequest>(v => v.Method == HttpMethod.Get)))
|
||||
.Returns<HttpRequest>(r => new HttpResponse(r, new HttpHeader(), recentFeed));
|
||||
|
||||
var releases = Subject.FetchRecent();
|
||||
|
||||
releases.Should().HaveCount(100);
|
||||
|
||||
var releaseInfo = releases.First();
|
||||
|
||||
releaseInfo.Title.Should().Be("Un.Petit.Boulot.2016.FRENCH.720p.BluRay.DTS.x264-LOST");
|
||||
releaseInfo.DownloadProtocol.Should().Be(DownloadProtocol.Usenet);
|
||||
releaseInfo.DownloadUrl.Should().Be("https://api.omgwtfnzbs.me/nzb/?id=8a2Bw&user=nzbdrone&api=nzbdrone");
|
||||
releaseInfo.InfoUrl.Should().Be("https://omgwtfnzbs.me/details.php?id=8a2Bw");
|
||||
releaseInfo.CommentUrl.Should().BeNullOrEmpty();
|
||||
releaseInfo.Indexer.Should().Be(Subject.Definition.Name);
|
||||
releaseInfo.PublishDate.Should().Be(DateTime.Parse("2017/01/09 00:16:54"));
|
||||
releaseInfo.Size.Should().Be(5354909355);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,4 +1,3 @@
|
||||
using System;
|
||||
using System.Linq;
|
||||
using System.Net.Http;
|
||||
using FluentAssertions;
|
||||
@@ -56,7 +55,7 @@ namespace NzbDrone.Core.Test.IndexerTests.PTPTests
|
||||
first.DownloadUrl.Should().Be("https://passthepopcorn.me/torrents.php?action=download&id=452135&authkey=00000000000000000000000000000000&torrent_pass=00000000000000000000000000000000");
|
||||
first.InfoUrl.Should().Be("https://passthepopcorn.me/torrents.php?id=148131&torrentid=452135");
|
||||
|
||||
first.PublishDate.Should().Be(DateTime.Parse("2016-10-18T23:40:59+0000").ToUniversalTime());
|
||||
// first.PublishDate.Should().Be(DateTime.Parse("2017-04-17T12:13:42+0000").ToUniversalTime()); stupid timezones
|
||||
first.Size.Should().Be(2466170624L);
|
||||
first.InfoHash.Should().BeNullOrEmpty();
|
||||
first.MagnetUrl.Should().BeNullOrEmpty();
|
||||
|
||||
@@ -135,21 +135,12 @@ namespace NzbDrone.Core.Test.IndexerTests.TorznabTests
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void should_use_best_pagesize_reported_by_caps()
|
||||
public void should_use_pagesize_reported_by_caps()
|
||||
{
|
||||
_caps.MaxPageSize = 30;
|
||||
_caps.DefaultPageSize = 25;
|
||||
|
||||
Subject.PageSize.Should().Be(30);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void should_not_use_pagesize_over_100_even_if_reported_in_caps()
|
||||
{
|
||||
_caps.MaxPageSize = 250;
|
||||
_caps.DefaultPageSize = 25;
|
||||
|
||||
Subject.PageSize.Should().Be(100);
|
||||
Subject.PageSize.Should().Be(25);
|
||||
}
|
||||
|
||||
[TestCase("http://localhost:9117/", "/api")]
|
||||
|
||||
@@ -49,14 +49,6 @@ namespace NzbDrone.Core.Test.Languages
|
||||
new object[] { 34, Language.Bengali },
|
||||
new object[] { 35, Language.Slovak },
|
||||
new object[] { 36, Language.Latvian },
|
||||
new object[] { 37, Language.SpanishLatino },
|
||||
new object[] { 38, Language.Catalan },
|
||||
new object[] { 39, Language.Croatian },
|
||||
new object[] { 40, Language.Serbian },
|
||||
new object[] { 41, Language.Bosnian },
|
||||
new object[] { 42, Language.Estonian },
|
||||
new object[] { 43, Language.Tamil },
|
||||
new object[] { 44, Language.Indonesian }
|
||||
};
|
||||
|
||||
public static object[] ToIntCases =
|
||||
@@ -100,14 +92,6 @@ namespace NzbDrone.Core.Test.Languages
|
||||
new object[] { Language.Bengali, 34 },
|
||||
new object[] { Language.Slovak, 35 },
|
||||
new object[] { Language.Latvian, 36 },
|
||||
new object[] { Language.SpanishLatino, 37 },
|
||||
new object[] { Language.Catalan, 38 },
|
||||
new object[] { Language.Croatian, 39 },
|
||||
new object[] { Language.Serbian, 40 },
|
||||
new object[] { Language.Bosnian, 41 },
|
||||
new object[] { Language.Estonian, 42 },
|
||||
new object[] { Language.Tamil, 43 },
|
||||
new object[] { Language.Indonesian, 44 }
|
||||
};
|
||||
|
||||
[Test]
|
||||
|
||||
@@ -445,58 +445,6 @@ namespace NzbDrone.Core.Test.MediaFiles
|
||||
.Verify(v => v.DeleteFolder(It.IsAny<string>(), true), Times.Never());
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void should_return_rejection_if_nothing_imported_and_contains_rar_file()
|
||||
{
|
||||
GivenValidMovie();
|
||||
|
||||
var path = @"C:\media\ba09030e-1234-1234-1234-123456789abc\[HorribleSubs] American Psycho (2000) [720p]\[HorribleSubs] American Psycho (2000) [720p].mkv".AsOsAgnostic();
|
||||
var imported = new List<ImportDecision>();
|
||||
|
||||
Mocker.GetMock<IMakeImportDecision>()
|
||||
.Setup(s => s.GetImportDecisions(It.IsAny<List<string>>(), It.IsAny<Movie>(), It.IsAny<DownloadClientItem>(), null, true, true))
|
||||
.Returns(imported);
|
||||
|
||||
Mocker.GetMock<IImportApprovedMovie>()
|
||||
.Setup(s => s.Import(It.IsAny<List<ImportDecision>>(), true, null, ImportMode.Auto))
|
||||
.Returns(imported.Select(i => new ImportResult(i)).ToList());
|
||||
|
||||
Mocker.GetMock<IDiskProvider>()
|
||||
.Setup(s => s.GetFiles(It.IsAny<string>(), SearchOption.AllDirectories))
|
||||
.Returns(new[] { _videoFiles.First().Replace(".ext", ".rar") });
|
||||
|
||||
var result = Subject.ProcessPath(path);
|
||||
|
||||
result.Count.Should().Be(1);
|
||||
result.First().Result.Should().Be(ImportResultType.Rejected);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void should_return_rejection_if_nothing_imported_and_contains_executable_file()
|
||||
{
|
||||
GivenValidMovie();
|
||||
|
||||
var path = @"C:\media\ba09030e-1234-1234-1234-123456789abc\[HorribleSubs] American Psycho (2000) [720p]\[HorribleSubs] American Psycho (2000) [720p].mkv".AsOsAgnostic();
|
||||
var imported = new List<ImportDecision>();
|
||||
|
||||
Mocker.GetMock<IMakeImportDecision>()
|
||||
.Setup(s => s.GetImportDecisions(It.IsAny<List<string>>(), It.IsAny<Movie>(), It.IsAny<DownloadClientItem>(), null, true, true))
|
||||
.Returns(imported);
|
||||
|
||||
Mocker.GetMock<IImportApprovedMovie>()
|
||||
.Setup(s => s.Import(It.IsAny<List<ImportDecision>>(), true, null, ImportMode.Auto))
|
||||
.Returns(imported.Select(i => new ImportResult(i)).ToList());
|
||||
|
||||
Mocker.GetMock<IDiskProvider>()
|
||||
.Setup(s => s.GetFiles(It.IsAny<string>(), SearchOption.AllDirectories))
|
||||
.Returns(new[] { _videoFiles.First().Replace(".ext", ".exe") });
|
||||
|
||||
var result = Subject.ProcessPath(path);
|
||||
|
||||
result.Count.Should().Be(1);
|
||||
result.First().Result.Should().Be(ImportResultType.Rejected);
|
||||
}
|
||||
|
||||
private void VerifyNoImport()
|
||||
{
|
||||
Mocker.GetMock<IImportApprovedMovie>().Verify(c => c.Import(It.IsAny<List<ImportDecision>>(), true, null, ImportMode.Auto),
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user