Sync Packages with Radarr

pull/1689/head
Qstick 4 years ago
parent 4fd772f62b
commit f5e2a447e9

@ -13,7 +13,7 @@ variables:
buildName: '$(Build.SourceBranchName).$(lidarrVersion)' buildName: '$(Build.SourceBranchName).$(lidarrVersion)'
sentryOrg: 'servarr' sentryOrg: 'servarr'
sentryUrl: 'https://sentry.servarr.com' sentryUrl: 'https://sentry.servarr.com'
dotnetVersion: '3.1.202' dotnetVersion: '3.1.301'
trigger: trigger:
branches: branches:

@ -268,7 +268,7 @@
"react/jsx-curly-spacing": [2, "never"], "react/jsx-curly-spacing": [2, "never"],
"react/jsx-equals-spacing": [2, "never"], "react/jsx-equals-spacing": [2, "never"],
"react/jsx-indent-props": [2, 2], "react/jsx-indent-props": [2, 2],
"react/jsx-indent": [2, 2], "react/jsx-indent": [2, 2, { "indentLogicalExpressions": true }],
"react/jsx-key": 2, "react/jsx-key": 2,
"react/jsx-no-bind": [2, { "allowArrowFunctions": true }], "react/jsx-no-bind": [2, { "allowArrowFunctions": true }],
"react/jsx-no-duplicate-props": [2, { "ignoreCase": true }], "react/jsx-no-duplicate-props": [2, { "ignoreCase": true }],

@ -10,8 +10,7 @@ gulp.task('build',
'webpack', 'webpack',
'copyHtml', 'copyHtml',
'copyFonts', 'copyFonts',
'copyImages', 'copyImages'
'copyJs'
) )
) )
); );

@ -5,17 +5,6 @@ const cache = require('gulp-cached');
const livereload = require('gulp-livereload'); const livereload = require('gulp-livereload');
const paths = require('./helpers/paths.js'); const paths = require('./helpers/paths.js');
gulp.task('copyJs', () => {
return gulp.src(
[
path.join(paths.src.root, 'polyfills.js')
], { base: paths.src.root })
.pipe(cache('copyJs'))
.pipe(print())
.pipe(gulp.dest(paths.dest.root))
.pipe(livereload());
});
gulp.task('copyHtml', () => { gulp.task('copyHtml', () => {
return gulp.src(paths.src.html, { base: paths.src.root }) return gulp.src(paths.src.html, { base: paths.src.root })
.pipe(cache('copyHtml')) .pipe(cache('copyHtml'))

@ -14,6 +14,7 @@ const frontendFolder = path.join(__dirname, '..');
const srcFolder = path.join(frontendFolder, 'src'); const srcFolder = path.join(frontendFolder, 'src');
const isProduction = process.argv.indexOf('--production') > -1; const isProduction = process.argv.indexOf('--production') > -1;
const isProfiling = isProduction && process.argv.indexOf('--profile') > -1; const isProfiling = isProduction && process.argv.indexOf('--profile') > -1;
const inlineWebWorkers = true;
const distFolder = path.resolve(frontendFolder, '..', '_output', uiFolder); const distFolder = path.resolve(frontendFolder, '..', '_output', uiFolder);
@ -124,7 +125,9 @@ const config = {
use: { use: {
loader: 'worker-loader', loader: 'worker-loader',
options: { options: {
name: '[name].js' name: '[name].js',
inline: inlineWebWorkers,
fallback: !inlineWebWorkers
} }
} }
}, },

@ -99,16 +99,16 @@ class RemoveQueueItemsModal extends Component {
{ {
blacklist && blacklist &&
<FormGroup> <FormGroup>
<FormLabel>Skip Redownload</FormLabel> <FormLabel>Skip Redownload</FormLabel>
<FormInputGroup <FormInputGroup
type={inputTypes.CHECK} type={inputTypes.CHECK}
name="skipredownload" name="skipredownload"
value={skipredownload} value={skipredownload}
helpText="Prevents Lidarr from trying download alternative releases for the removed items" helpText="Prevents Lidarr from trying download alternative releases for the removed items"
onChange={this.onSkipReDownloadChange} onChange={this.onSkipReDownloadChange}
/> />
</FormGroup> </FormGroup>
} }
</ModalBody> </ModalBody>

@ -71,10 +71,10 @@ class TrackActionsCell extends Component {
} }
{ {
trackFilePath && trackFilePath &&
<IconButton <IconButton
name={icons.DELETE} name={icons.DELETE}
onPress={this.onDeleteFilePress} onPress={this.onDeleteFilePress}
/> />
} }
<FileDetailsModal <FileDetailsModal

@ -108,7 +108,7 @@ class ArtistIndexBannerOptionsModalContent extends Component {
return ( return (
<ModalContent onModalClose={onModalClose}> <ModalContent onModalClose={onModalClose}>
<ModalHeader> <ModalHeader>
Options Options
</ModalHeader> </ModalHeader>
<ModalBody> <ModalBody>

@ -127,10 +127,10 @@ class ArtistIndexOverview extends Component {
<div className={styles.posterContainer}> <div className={styles.posterContainer}>
{ {
status === 'ended' && status === 'ended' &&
<div <div
className={styles.ended} className={styles.ended}
title="Ended" title="Ended"
/> />
} }
<Link <Link

@ -183,19 +183,19 @@ function ArtistIndexOverviewInfo(props) {
<div className={styles.infos}> <div className={styles.infos}>
{ {
!!nextAiring && !!nextAiring &&
<ArtistIndexOverviewInfoRow <ArtistIndexOverviewInfoRow
title={formatDateTime(nextAiring, longDateFormat, timeFormat)} title={formatDateTime(nextAiring, longDateFormat, timeFormat)}
iconName={icons.SCHEDULED} iconName={icons.SCHEDULED}
label={getRelativeDate( label={getRelativeDate(
nextAiring, nextAiring,
shortDateFormat, shortDateFormat,
showRelativeDates, showRelativeDates,
{ {
timeFormat, timeFormat,
timeForToday: true timeForToday: true
} }
)} )}
/> />
} }
{ {

@ -11,7 +11,7 @@ function NoArtist(props) {
return ( return (
<div> <div>
<div className={styles.message}> <div className={styles.message}>
All artists are hidden due to the applied filter. All artists are hidden due to the applied filter.
</div> </div>
</div> </div>
); );

@ -135,9 +135,9 @@ class CalendarPage extends Component {
> >
{ {
artistError && artistError &&
<div className={styles.errorMessage}> <div className={styles.errorMessage}>
{getErrorMessage(artistError, 'Failed to load artist from API')} {getErrorMessage(artistError, 'Failed to load artist from API')}
</div> </div>
} }
{ {

@ -94,11 +94,11 @@ class CalendarEvent extends Component {
{ {
!queueItem && grabbed && !queueItem && grabbed &&
<Icon <Icon
className={styles.statusIcon} className={styles.statusIcon}
name={icons.DOWNLOADING} name={icons.DOWNLOADING}
title="Album is downloading" title="Album is downloading"
/> />
} }
</div> </div>

@ -24,7 +24,7 @@ function CustomFiltersModalContent(props) {
return ( return (
<ModalContent onModalClose={onModalClose}> <ModalContent onModalClose={onModalClose}>
<ModalHeader> <ModalHeader>
Custom Filters Custom Filters
</ModalHeader> </ModalHeader>
<ModalBody> <ModalBody>
@ -58,7 +58,7 @@ function CustomFiltersModalContent(props) {
<Button <Button
onPress={onModalClose} onPress={onModalClose}
> >
Close Close
</Button> </Button>
</ModalFooter> </ModalFooter>
</ModalContent> </ModalContent>

@ -59,7 +59,7 @@ class RootFolderSelectInputConnector extends Component {
// //
// Lifecycle // Lifecycle
componentWillMount() { UNSAFE_componentWillMount() {
const { const {
value, value,
values, values,

@ -2,7 +2,7 @@ import PropTypes from 'prop-types';
import React from 'react'; import React from 'react';
import styles from './LoadingIndicator.css'; import styles from './LoadingIndicator.css';
function LoadingIndicator({ className, size }) { function LoadingIndicator({ className, rippleClassName, size }) {
const sizeInPx = `${size}px`; const sizeInPx = `${size}px`;
const width = sizeInPx; const width = sizeInPx;
const height = sizeInPx; const height = sizeInPx;
@ -17,17 +17,17 @@ function LoadingIndicator({ className, size }) {
style={{ width, height }} style={{ width, height }}
> >
<div <div
className={styles.ripple} className={rippleClassName}
style={{ width, height }} style={{ width, height }}
/> />
<div <div
className={styles.ripple} className={rippleClassName}
style={{ width, height }} style={{ width, height }}
/> />
<div <div
className={styles.ripple} className={rippleClassName}
style={{ width, height }} style={{ width, height }}
/> />
</div> </div>
@ -37,11 +37,13 @@ function LoadingIndicator({ className, size }) {
LoadingIndicator.propTypes = { LoadingIndicator.propTypes = {
className: PropTypes.string, className: PropTypes.string,
rippleClassName: PropTypes.string,
size: PropTypes.number size: PropTypes.number
}; };
LoadingIndicator.defaultProps = { LoadingIndicator.defaultProps = {
className: styles.loading, className: styles.loading,
rippleClassName: styles.ripple,
size: 50 size: 50
}; };

@ -61,7 +61,7 @@ class FilterMenuContent extends Component {
{ {
showCustomFilters && showCustomFilters &&
<MenuItem onPress={onCustomFiltersPress}> <MenuItem onPress={onCustomFiltersPress}>
Custom Filters Custom Filters
</MenuItem> </MenuItem>
} }
</MenuContent> </MenuContent>

@ -1,6 +1,7 @@
import PropTypes from 'prop-types'; import PropTypes from 'prop-types';
import React from 'react'; import React, { useEffect } from 'react';
import { kinds, sizes } from 'Helpers/Props'; import { kinds, sizes } from 'Helpers/Props';
import keyboardShortcuts from 'Components/keyboardShortcuts';
import Button from 'Components/Link/Button'; import Button from 'Components/Link/Button';
import SpinnerButton from 'Components/Link/SpinnerButton'; import SpinnerButton from 'Components/Link/SpinnerButton';
import Modal from 'Components/Modal/Modal'; import Modal from 'Components/Modal/Modal';
@ -21,9 +22,19 @@ function ConfirmModal(props) {
hideCancelButton, hideCancelButton,
isSpinning, isSpinning,
onConfirm, onConfirm,
onCancel onCancel,
bindShortcut,
unbindShortcut
} = props; } = props;
useEffect(() => {
if (isOpen) {
bindShortcut('enter', onConfirm);
} else {
unbindShortcut('enter', onConfirm);
}
}, [onConfirm]);
return ( return (
<Modal <Modal
isOpen={isOpen} isOpen={isOpen}
@ -49,7 +60,7 @@ function ConfirmModal(props) {
} }
<SpinnerButton <SpinnerButton
data-autofocus={true} autoFocus={true}
kind={kind} kind={kind}
isSpinning={isSpinning} isSpinning={isSpinning}
onPress={onConfirm} onPress={onConfirm}
@ -74,7 +85,9 @@ ConfirmModal.propTypes = {
hideCancelButton: PropTypes.bool, hideCancelButton: PropTypes.bool,
isSpinning: PropTypes.bool.isRequired, isSpinning: PropTypes.bool.isRequired,
onConfirm: PropTypes.func.isRequired, onConfirm: PropTypes.func.isRequired,
onCancel: PropTypes.func.isRequired onCancel: PropTypes.func.isRequired,
bindShortcut: PropTypes.func.isRequired,
unbindShortcut: PropTypes.func.isRequired
}; };
ConfirmModal.defaultProps = { ConfirmModal.defaultProps = {
@ -85,4 +98,4 @@ ConfirmModal.defaultProps = {
isSpinning: false isSpinning: false
}; };
export default ConfirmModal; export default keyboardShortcuts(ConfirmModal);

@ -1,6 +1,7 @@
import PropTypes from 'prop-types'; import PropTypes from 'prop-types';
import React, { Component } from 'react'; import React, { Component } from 'react';
import ReactDOM from 'react-dom'; import ReactDOM from 'react-dom';
import FocusLock from 'react-focus-lock';
import classNames from 'classnames'; import classNames from 'classnames';
import elementClass from 'element-class'; import elementClass from 'element-class';
import getUniqueElememtId from 'Utilities/getUniqueElementId'; import getUniqueElememtId from 'Utilities/getUniqueElementId';
@ -181,31 +182,33 @@ class Modal extends Component {
} }
return ReactDOM.createPortal( return ReactDOM.createPortal(
<div <FocusLock disabled={false}>
className={styles.modalContainer}
>
<div <div
ref={this._setBackgroundRef} className={styles.modalContainer}
className={backdropClassName}
onMouseDown={this.onBackdropBeginPress}
onMouseUp={this.onBackdropEndPress}
> >
<div <div
className={classNames( ref={this._setBackgroundRef}
className, className={backdropClassName}
styles[size] onMouseDown={this.onBackdropBeginPress}
)} onMouseUp={this.onBackdropEndPress}
style={style}
> >
<ErrorBoundary <div
errorComponent={ModalError} className={classNames(
onModalClose={onModalClose} className,
styles[size]
)}
style={style}
> >
{children} <ErrorBoundary
</ErrorBoundary> errorComponent={ModalError}
onModalClose={onModalClose}
>
{children}
</ErrorBoundary>
</div>
</div> </div>
</div> </div>
</div>, </FocusLock>,
this._node this._node
); );
} }

@ -3,6 +3,18 @@
align-items: center; align-items: center;
} }
.loading {
margin-top: 18px;
margin-bottom: 18px;
text-align: center;
}
.ripple {
composes: ripple from '~Components/Loading/LoadingIndicator.css';
border: 2px solid $toolbarColor;
}
.input { .input {
margin-left: 8px; margin-left: 8px;
width: 200px; width: 200px;

@ -74,7 +74,11 @@ class ArtistSearchInput extends Component {
if (item.type === LOADING_TYPE) { if (item.type === LOADING_TYPE) {
return ( return (
<LoadingIndicator /> <LoadingIndicator
className={styles.loading}
rippleClassName={styles.ripple}
size={30}
/>
); );
} }
@ -124,7 +128,7 @@ class ArtistSearchInput extends Component {
highlightedSuggestionIndex highlightedSuggestionIndex
} = this._autosuggest.state; } = this._autosuggest.state;
if (!suggestions.length || suggestions[0].type === LOADING_TYPE || highlightedSectionIndex) { if (!suggestions.length || highlightedSectionIndex) {
this.props.onGoToAddNewArtist(value); this.props.onGoToAddNewArtist(value);
this._autosuggest.input.blur(); this._autosuggest.input.blur();
this.reset(); this.reset();

@ -6,7 +6,6 @@ const fuseOptions = {
threshold: 0.3, threshold: 0.3,
location: 0, location: 0,
distance: 100, distance: 100,
maxPatternLength: 32,
minMatchCharLength: 1, minMatchCharLength: 1,
keys: [ keys: [
'artistName', 'artistName',

@ -17,12 +17,18 @@ class Scroller extends Component {
componentDidMount() { componentDidMount() {
const { const {
scrollDirection,
autoFocus,
scrollTop scrollTop
} = this.props; } = this.props;
if (this.props.scrollTop != null) { if (this.props.scrollTop != null) {
this._scroller.scrollTop = scrollTop; this._scroller.scrollTop = scrollTop;
} }
if (autoFocus && scrollDirection !== scrollDirections.NONE) {
this._scroller.focus({ preventScroll: true });
}
} }
// //
@ -58,6 +64,7 @@ class Scroller extends Component {
styles[scrollDirection], styles[scrollDirection],
autoScroll && styles.autoScroll autoScroll && styles.autoScroll
)} )}
tabIndex={-1}
{...otherProps} {...otherProps}
> >
{children} {children}
@ -70,6 +77,7 @@ class Scroller extends Component {
Scroller.propTypes = { Scroller.propTypes = {
className: PropTypes.string, className: PropTypes.string,
scrollDirection: PropTypes.oneOf(scrollDirections.all).isRequired, scrollDirection: PropTypes.oneOf(scrollDirections.all).isRequired,
autoFocus: PropTypes.bool.isRequired,
autoScroll: PropTypes.bool.isRequired, autoScroll: PropTypes.bool.isRequired,
scrollTop: PropTypes.number, scrollTop: PropTypes.number,
children: PropTypes.node, children: PropTypes.node,
@ -79,6 +87,7 @@ Scroller.propTypes = {
Scroller.defaultProps = { Scroller.defaultProps = {
scrollDirection: scrollDirections.VERTICAL, scrollDirection: scrollDirections.VERTICAL,
autoFocus: true,
autoScroll: true, autoScroll: true,
registerScroller: () => {} registerScroller: () => {}
}; };

@ -136,7 +136,7 @@ class TableOptionsModal extends Component {
isOpen ? isOpen ?
<ModalContent onModalClose={onModalClose}> <ModalContent onModalClose={onModalClose}>
<ModalHeader> <ModalHeader>
Table Options Table Options
</ModalHeader> </ModalHeader>
<ModalBody> <ModalBody>
@ -231,7 +231,7 @@ class TableOptionsModal extends Component {
<Button <Button
onPress={onModalClose} onPress={onModalClose}
> >
Close Close
</Button> </Button>
</ModalFooter> </ModalFooter>
</ModalContent> : </ModalContent> :

@ -8,6 +8,16 @@ export const shortcuts = {
name: 'Open This Modal' name: 'Open This Modal'
}, },
CLOSE_MODAL: {
key: 'Esc',
name: 'Close Current Modal'
},
ACCEPT_CONFIRM_MODAL: {
key: 'Enter',
name: 'Accept Confirmation Modal'
},
ARTIST_SEARCH_INPUT: { ARTIST_SEARCH_INPUT: {
key: 's', key: 's',
name: 'Focus Search Box' name: 'Focus Search Box'

@ -72,9 +72,9 @@ class ConfirmImportModalContent extends Component {
{ {
!isFetching && isPopulated && !isFetching && isPopulated &&
<ModalHeader> <ModalHeader>
Are you sure? Are you sure?
</ModalHeader> </ModalHeader>
} }
<ModalBody> <ModalBody>

@ -177,7 +177,7 @@ function InteractiveSearch(props) {
{ {
totalReleasesCount !== items.length && !!items.length ? totalReleasesCount !== items.length && !!items.length ?
<div className={styles.filteredMessage}> <div className={styles.filteredMessage}>
Some results are hidden by the applied filter Some results are hidden by the applied filter
</div> : </div> :
null null
} }

@ -103,11 +103,11 @@ class AddNewAlbumSearchResult extends Component {
<div className={styles.overlay}> <div className={styles.overlay}>
{ {
!isSmallScreen && !isSmallScreen &&
<AlbumCover <AlbumCover
className={styles.poster} className={styles.poster}
images={images} images={images}
size={250} size={250}
/> />
} }
<div className={styles.content}> <div className={styles.content}>
@ -116,7 +116,7 @@ class AddNewAlbumSearchResult extends Component {
{ {
!!disambiguation && !!disambiguation &&
<span className={styles.year}>({disambiguation})</span> <span className={styles.year}>({disambiguation})</span>
} }
{ {

@ -124,7 +124,7 @@ class AddNewArtistSearchResult extends Component {
{ {
!!disambiguation && !!disambiguation &&
<span className={styles.year}>({disambiguation})</span> <span className={styles.year}>({disambiguation})</span>
} }
{ {

@ -44,90 +44,90 @@ function ProxySettings(props) {
{ {
proxyEnabled.value && proxyEnabled.value &&
<div> <div>
<FormGroup> <FormGroup>
<FormLabel>Proxy Type</FormLabel> <FormLabel>Proxy Type</FormLabel>
<FormInputGroup <FormInputGroup
type={inputTypes.SELECT} type={inputTypes.SELECT}
name="proxyType" name="proxyType"
values={proxyTypeOptions} values={proxyTypeOptions}
onChange={onInputChange} onChange={onInputChange}
{...proxyType} {...proxyType}
/> />
</FormGroup> </FormGroup>
<FormGroup> <FormGroup>
<FormLabel>Hostname</FormLabel> <FormLabel>Hostname</FormLabel>
<FormInputGroup <FormInputGroup
type={inputTypes.TEXT} type={inputTypes.TEXT}
name="proxyHostname" name="proxyHostname"
onChange={onInputChange} onChange={onInputChange}
{...proxyHostname} {...proxyHostname}
/> />
</FormGroup> </FormGroup>
<FormGroup> <FormGroup>
<FormLabel>Port</FormLabel> <FormLabel>Port</FormLabel>
<FormInputGroup <FormInputGroup
type={inputTypes.NUMBER} type={inputTypes.NUMBER}
name="proxyPort" name="proxyPort"
min={1} min={1}
max={65535} max={65535}
onChange={onInputChange} onChange={onInputChange}
{...proxyPort} {...proxyPort}
/> />
</FormGroup> </FormGroup>
<FormGroup> <FormGroup>
<FormLabel>Username</FormLabel> <FormLabel>Username</FormLabel>
<FormInputGroup <FormInputGroup
type={inputTypes.TEXT} type={inputTypes.TEXT}
name="proxyUsername" name="proxyUsername"
helpText="You only need to enter a username and password if one is required. Leave them blank otherwise." helpText="You only need to enter a username and password if one is required. Leave them blank otherwise."
onChange={onInputChange} onChange={onInputChange}
{...proxyUsername} {...proxyUsername}
/> />
</FormGroup> </FormGroup>
<FormGroup> <FormGroup>
<FormLabel>Password</FormLabel> <FormLabel>Password</FormLabel>
<FormInputGroup <FormInputGroup
type={inputTypes.PASSWORD} type={inputTypes.PASSWORD}
name="proxyPassword" name="proxyPassword"
helpText="You only need to enter a username and password if one is required. Leave them blank otherwise." helpText="You only need to enter a username and password if one is required. Leave them blank otherwise."
onChange={onInputChange} onChange={onInputChange}
{...proxyPassword} {...proxyPassword}
/> />
</FormGroup> </FormGroup>
<FormGroup> <FormGroup>
<FormLabel>Ignored Addresses</FormLabel> <FormLabel>Ignored Addresses</FormLabel>
<FormInputGroup <FormInputGroup
type={inputTypes.TEXT} type={inputTypes.TEXT}
name="proxyBypassFilter" name="proxyBypassFilter"
helpText="Use ',' as a separator, and '*.' as a wildcard for subdomains" helpText="Use ',' as a separator, and '*.' as a wildcard for subdomains"
onChange={onInputChange} onChange={onInputChange}
{...proxyBypassFilter} {...proxyBypassFilter}
/> />
</FormGroup> </FormGroup>
<FormGroup size={sizes.MEDIUM}> <FormGroup size={sizes.MEDIUM}>
<FormLabel>Bypass Proxy for Local Addresses</FormLabel> <FormLabel>Bypass Proxy for Local Addresses</FormLabel>
<FormInputGroup <FormInputGroup
type={inputTypes.CHECK} type={inputTypes.CHECK}
name="proxyBypassLocalAddresses" name="proxyBypassLocalAddresses"
onChange={onInputChange} onChange={onInputChange}
{...proxyBypassLocalAddresses} {...proxyBypassLocalAddresses}
/> />
</FormGroup> </FormGroup>
</div> </div>
} }
</FieldSet> </FieldSet>
); );

@ -93,32 +93,32 @@ class SecuritySettings extends Component {
{ {
authenticationEnabled && authenticationEnabled &&
<FormGroup> <FormGroup>
<FormLabel>Username</FormLabel> <FormLabel>Username</FormLabel>
<FormInputGroup <FormInputGroup
type={inputTypes.TEXT} type={inputTypes.TEXT}
name="username" name="username"
helpTextWarning="Requires restart to take effect" helpTextWarning="Requires restart to take effect"
onChange={onInputChange} onChange={onInputChange}
{...username} {...username}
/> />
</FormGroup> </FormGroup>
} }
{ {
authenticationEnabled && authenticationEnabled &&
<FormGroup> <FormGroup>
<FormLabel>Password</FormLabel> <FormLabel>Password</FormLabel>
<FormInputGroup <FormInputGroup
type={inputTypes.PASSWORD} type={inputTypes.PASSWORD}
name="password" name="password"
helpTextWarning="Requires restart to take effect" helpTextWarning="Requires restart to take effect"
onChange={onInputChange} onChange={onInputChange}
{...password} {...password}
/> />
</FormGroup> </FormGroup>
} }
<FormGroup> <FormGroup>

@ -72,58 +72,58 @@ function UpdateSettings(props) {
{ {
!isWindows && !isWindows &&
<div> <div>
<FormGroup
advancedSettings={advancedSettings}
isAdvanced={true}
size={sizes.MEDIUM}
>
<FormLabel>Automatic</FormLabel>
<FormInputGroup
type={inputTypes.CHECK}
name="updateAutomatically"
helpText="Automatically download and install updates. You will still be able to install from System: Updates"
onChange={onInputChange}
{...updateAutomatically}
/>
</FormGroup>
<FormGroup
advancedSettings={advancedSettings}
isAdvanced={true}
>
<FormLabel>Mechanism</FormLabel>
<FormInputGroup
type={inputTypes.SELECT}
name="updateMechanism"
values={updateOptions}
helpText="Use Lidarr's built-in updater or a script"
helpLink="https://github.com/Lidarr/Lidarr/wiki/Updating"
onChange={onInputChange}
{...updateMechanism}
/>
</FormGroup>
{
updateMechanism.value === 'script' &&
<FormGroup <FormGroup
advancedSettings={advancedSettings} advancedSettings={advancedSettings}
isAdvanced={true} isAdvanced={true}
size={sizes.MEDIUM}
> >
<FormLabel>Script Path</FormLabel> <FormLabel>Automatic</FormLabel>
<FormInputGroup <FormInputGroup
type={inputTypes.TEXT} type={inputTypes.CHECK}
name="updateScriptPath" name="updateAutomatically"
helpText="Path to a custom script that takes an extracted update package and handle the remainder of the update process" helpText="Automatically download and install updates. You will still be able to install from System: Updates"
onChange={onInputChange} onChange={onInputChange}
{...updateScriptPath} {...updateAutomatically}
/> />
</FormGroup> </FormGroup>
}
</div> <FormGroup
advancedSettings={advancedSettings}
isAdvanced={true}
>
<FormLabel>Mechanism</FormLabel>
<FormInputGroup
type={inputTypes.SELECT}
name="updateMechanism"
values={updateOptions}
helpText="Use Lidarr's built-in updater or a script"
helpLink="https://github.com/Lidarr/Lidarr/wiki/Updating"
onChange={onInputChange}
{...updateMechanism}
/>
</FormGroup>
{
updateMechanism.value === 'script' &&
<FormGroup
advancedSettings={advancedSettings}
isAdvanced={true}
>
<FormLabel>Script Path</FormLabel>
<FormInputGroup
type={inputTypes.TEXT}
name="updateScriptPath"
helpText="Path to a custom script that takes an extracted update package and handle the remainder of the update process"
onChange={onInputChange}
{...updateScriptPath}
/>
</FormGroup>
}
</div>
} }
</FieldSet> </FieldSet>
); );

@ -199,23 +199,23 @@ function EditImportListModalContent(props) {
{ {
!!fields && !!fields.length && !!fields && !!fields.length &&
<div> <div>
{ {
fields.map((field) => { fields.map((field) => {
return ( return (
<ProviderFieldFormGroup <ProviderFieldFormGroup
key={field.name} key={field.name}
advancedSettings={advancedSettings} advancedSettings={advancedSettings}
provider="importList" provider="importList"
providerData={item} providerData={item}
section="settings.importLists" section="settings.importLists"
{...field} {...field}
onChange={onFieldChange} onChange={onFieldChange}
/> />
); );
}) })
} }
</div> </div>
} }
</Form> </Form>

@ -96,12 +96,12 @@ class Indexer extends Component {
{ {
!enableRss && !enableAutomaticSearch && !enableInteractiveSearch && !enableRss && !enableAutomaticSearch && !enableInteractiveSearch &&
<Label <Label
kind={kinds.DISABLED} kind={kinds.DISABLED}
outline={true} outline={true}
> >
Disabled Disabled
</Label> </Label>
} }
</div> </div>

@ -43,23 +43,23 @@ function MetadataProvider(props) {
<Form> <Form>
{ {
advancedSettings && advancedSettings &&
<FieldSet legend="Metadata Provider Source"> <FieldSet legend="Metadata Provider Source">
<FormGroup <FormGroup
advancedSettings={advancedSettings} advancedSettings={advancedSettings}
isAdvanced={true} isAdvanced={true}
> >
<FormLabel>Metadata Source</FormLabel> <FormLabel>Metadata Source</FormLabel>
<FormInputGroup <FormInputGroup
type={inputTypes.TEXT} type={inputTypes.TEXT}
name="metadataSource" name="metadataSource"
helpText="Alternative Metadata Source (Leave blank for default)" helpText="Alternative Metadata Source (Leave blank for default)"
helpLink="https://github.com/Lidarr/Lidarr/wiki/Metadata-Source" helpLink="https://github.com/Lidarr/Lidarr/wiki/Metadata-Source"
onChange={onInputChange} onChange={onInputChange}
{...settings.metadataSource} {...settings.metadataSource}
/> />
</FormGroup> </FormGroup>
</FieldSet> </FieldSet>
} }
<FieldSet legend="Write Metadata to Audio Files"> <FieldSet legend="Write Metadata to Audio Files">

@ -141,12 +141,12 @@ class Notification extends Component {
{ {
!onGrab && !onReleaseImport && !onRename && !onTrackRetag && !onGrab && !onReleaseImport && !onRename && !onTrackRetag &&
!onHealthIssue && !onDownloadFailure && !onImportFailure && !onHealthIssue && !onDownloadFailure && !onImportFailure &&
<Label <Label
kind={kinds.DISABLED} kind={kinds.DISABLED}
outline={true} outline={true}
> >
Disabled Disabled
</Label> </Label>
} }
<EditNotificationModalConnector <EditNotificationModalConnector

@ -1,6 +1,7 @@
import PropTypes from 'prop-types'; import PropTypes from 'prop-types';
import React from 'react'; import React, { useEffect } from 'react';
import { kinds } from 'Helpers/Props'; import { kinds } from 'Helpers/Props';
import keyboardShortcuts from 'Components/keyboardShortcuts';
import Button from 'Components/Link/Button'; import Button from 'Components/Link/Button';
import Modal from 'Components/Modal/Modal'; import Modal from 'Components/Modal/Modal';
import ModalContent from 'Components/Modal/ModalContent'; import ModalContent from 'Components/Modal/ModalContent';
@ -12,9 +13,14 @@ function PendingChangesModal(props) {
const { const {
isOpen, isOpen,
onConfirm, onConfirm,
onCancel onCancel,
bindShortcut
} = props; } = props;
useEffect(() => {
bindShortcut('enter', onConfirm);
}, [onConfirm]);
return ( return (
<Modal <Modal
isOpen={isOpen} isOpen={isOpen}
@ -36,6 +42,7 @@ function PendingChangesModal(props) {
</Button> </Button>
<Button <Button
autoFocus={true}
kind={kinds.DANGER} kind={kinds.DANGER}
onPress={onConfirm} onPress={onConfirm}
> >
@ -52,11 +59,12 @@ PendingChangesModal.propTypes = {
isOpen: PropTypes.bool.isRequired, isOpen: PropTypes.bool.isRequired,
kind: PropTypes.oneOf(kinds.all), kind: PropTypes.oneOf(kinds.all),
onConfirm: PropTypes.func.isRequired, onConfirm: PropTypes.func.isRequired,
onCancel: PropTypes.func.isRequired onCancel: PropTypes.func.isRequired,
bindShortcut: PropTypes.func.isRequired
}; };
PendingChangesModal.defaultProps = { PendingChangesModal.defaultProps = {
kind: kinds.PRIMARY kind: kinds.PRIMARY
}; };
export default PendingChangesModal; export default keyboardShortcuts(PendingChangesModal);

@ -174,7 +174,7 @@ class EditQualityProfileModalContent extends Component {
upgradeAllowed.value && upgradeAllowed.value &&
<FormGroup size={sizes.EXTRA_SMALL}> <FormGroup size={sizes.EXTRA_SMALL}>
<FormLabel size={sizes.SMALL}> <FormLabel size={sizes.SMALL}>
Upgrade Until Upgrade Until
</FormLabel> </FormLabel>
<FormInputGroup <FormInputGroup

@ -167,7 +167,7 @@ function TagDetailsModalContent(props) {
isDisabled={isTagUsed} isDisabled={isTagUsed}
onPress={onDeleteTagPress} onPress={onDeleteTagPress}
> >
Delete Delete
</Button> </Button>
} }

@ -200,7 +200,7 @@ class RestoreBackupModalContent extends Component {
</div> </div>
<Button onPress={onModalClose}> <Button onPress={onModalClose}>
Cancel Cancel
</Button> </Button>
<SpinnerButton <SpinnerButton
@ -209,7 +209,7 @@ class RestoreBackupModalContent extends Component {
isSpinning={isRestoring} isSpinning={isRestoring}
onPress={this.onRestorePress} onPress={this.onRestorePress}
> >
Restore Restore
</SpinnerButton> </SpinnerButton>
</ModalFooter> </ModalFooter>
</ModalContent> </ModalContent>

@ -76,45 +76,45 @@ function LogsTable(props) {
<PageContentBodyConnector> <PageContentBodyConnector>
{ {
isFetching && !isPopulated && isFetching && !isPopulated &&
<LoadingIndicator /> <LoadingIndicator />
} }
{ {
isPopulated && !error && !items.length && isPopulated && !error && !items.length &&
<div> <div>
No logs found No logs found
</div> </div>
} }
{ {
isPopulated && !error && !!items.length && isPopulated && !error && !!items.length &&
<div> <div>
<Table <Table
columns={columns} columns={columns}
canModifyColumns={false} canModifyColumns={false}
{...otherProps} {...otherProps}
> >
<TableBody> <TableBody>
{ {
items.map((item) => { items.map((item) => {
return ( return (
<LogsTableRow <LogsTableRow
key={item.id} key={item.id}
columns={columns} columns={columns}
{...item} {...item}
/> />
); );
}) })
} }
</TableBody> </TableBody>
</Table> </Table>
<TablePager <TablePager
totalRecords={totalRecords} totalRecords={totalRecords}
isFetching={isFetching} isFetching={isFetching}
{...otherProps} {...otherProps}
/> />
</div> </div>
} }
</PageContentBodyConnector> </PageContentBodyConnector>
</PageContent> </PageContent>

@ -54,27 +54,27 @@ function QueuedTasks(props) {
<FieldSet legend="Queue"> <FieldSet legend="Queue">
{ {
isFetching && !isPopulated && isFetching && !isPopulated &&
<LoadingIndicator /> <LoadingIndicator />
} }
{ {
isPopulated && isPopulated &&
<Table <Table
columns={columns} columns={columns}
> >
<TableBody> <TableBody>
{ {
items.map((item) => { items.map((item) => {
return ( return (
<QueuedTaskRowConnector <QueuedTaskRowConnector
key={item.id} key={item.id}
{...item} {...item}
/> />
); );
}) })
} }
</TableBody> </TableBody>
</Table> </Table>
} }
</FieldSet> </FieldSet>
); );

@ -49,27 +49,27 @@ function ScheduledTasks(props) {
<FieldSet legend="Scheduled"> <FieldSet legend="Scheduled">
{ {
isFetching && !isPopulated && isFetching && !isPopulated &&
<LoadingIndicator /> <LoadingIndicator />
} }
{ {
isPopulated && isPopulated &&
<Table <Table
columns={columns} columns={columns}
> >
<TableBody> <TableBody>
{ {
items.map((item) => { items.map((item) => {
return ( return (
<ScheduledTaskRowConnector <ScheduledTaskRowConnector
key={item.id} key={item.id}
{...item} {...item}
/> />
); );
}) })
} }
</TableBody> </TableBody>
</Table> </Table>
} }
</FieldSet> </FieldSet>
); );

@ -79,6 +79,5 @@
</body> </body>
<script src="/initialize.js" data-no-hash></script> <script src="/initialize.js" data-no-hash></script>
<script src="/polyfills.js"></script>
<!-- webpack bundles body --> <!-- webpack bundles body -->
</html> </html>

@ -1,4 +1,6 @@
import './preload.js'; import './preload';
import './polyfills';
import React from 'react'; import React from 'react';
import { render } from 'react-dom'; import { render } from 'react-dom';
import { createBrowserHistory } from 'history'; import { createBrowserHistory } from 'history';

@ -20,48 +20,47 @@
"license": "GPL-3.0", "license": "GPL-3.0",
"readmeFilename": "readme.md", "readmeFilename": "readme.md",
"dependencies": { "dependencies": {
"@babel/core": "7.7.5", "@babel/core": "7.9.6",
"@babel/plugin-proposal-class-properties": "7.7.4", "@babel/plugin-proposal-class-properties": "7.8.3",
"@babel/plugin-proposal-decorators": "7.7.4", "@babel/plugin-proposal-decorators": "7.8.3",
"@babel/plugin-proposal-export-default-from": "7.7.4", "@babel/plugin-proposal-export-default-from": "7.8.3",
"@babel/plugin-proposal-export-namespace-from": "7.7.4", "@babel/plugin-proposal-export-namespace-from": "7.8.3",
"@babel/plugin-proposal-function-sent": "7.7.4", "@babel/plugin-proposal-function-sent": "7.8.3",
"@babel/plugin-proposal-nullish-coalescing-operator": "7.7.4", "@babel/plugin-proposal-nullish-coalescing-operator": "7.8.3",
"@babel/plugin-proposal-numeric-separator": "7.7.4", "@babel/plugin-proposal-numeric-separator": "7.8.3",
"@babel/plugin-proposal-optional-chaining": "7.7.5", "@babel/plugin-proposal-optional-chaining": "7.9.0",
"@babel/plugin-proposal-throw-expressions": "7.7.4", "@babel/plugin-proposal-throw-expressions": "7.8.3",
"@babel/plugin-syntax-dynamic-import": "7.7.4", "@babel/plugin-syntax-dynamic-import": "7.8.3",
"@babel/preset-env": "7.7.5", "@babel/preset-env": "7.9.6",
"@babel/preset-react": "7.7.4", "@babel/preset-react": "7.9.4",
"@fortawesome/fontawesome-free": "5.11.2", "@fortawesome/fontawesome-free": "5.13.0",
"@fortawesome/fontawesome-svg-core": "1.2.25", "@fortawesome/fontawesome-svg-core": "1.2.28",
"@fortawesome/free-regular-svg-icons": "5.11.2", "@fortawesome/free-regular-svg-icons": "5.13.0",
"@fortawesome/free-solid-svg-icons": "5.11.2", "@fortawesome/free-solid-svg-icons": "5.13.0",
"@fortawesome/react-fontawesome": "0.1.8", "@fortawesome/react-fontawesome": "0.1.9",
"@microsoft/signalr": "3.1.0", "@microsoft/signalr": "3.1.4",
"@sentry/browser": "5.11.0", "@sentry/browser": "5.15.5",
"@sentry/integrations": "5.11.0", "@sentry/integrations": "5.15.5",
"ansi-colors": "4.1.1", "ansi-colors": "4.1.1",
"autoprefixer": "9.7.3", "autoprefixer": "9.7.5",
"babel-eslint": "10.0.3", "babel-eslint": "10.1.0",
"babel-loader": "8.0.6", "babel-loader": "8.1.0",
"babel-plugin-inline-classnames": "2.0.1", "babel-plugin-inline-classnames": "2.0.1",
"babel-plugin-transform-react-remove-prop-types": "0.4.24", "babel-plugin-transform-react-remove-prop-types": "0.4.24",
"classnames": "2.2.6", "classnames": "2.2.6",
"clipboard": "2.0.4", "clipboard": "2.0.6",
"connected-react-router": "6.6.1", "connected-react-router": "6.8.0",
"core-js": "3", "core-js": "3",
"create-react-class": "15.6.3", "css-loader": "3.4.2",
"css-loader": "3.2.1",
"del": "5.1.0", "del": "5.1.0",
"element-class": "0.2.2", "element-class": "0.2.2",
"eslint": "6.8.0", "eslint": "7.1.0",
"eslint-plugin-filenames": "1.3.2", "eslint-plugin-filenames": "1.3.2",
"eslint-plugin-react": "7.18.0", "eslint-plugin-react": "7.20.0",
"esprint": "0.6.0", "esprint": "0.7.0",
"file-loader": "5.0.2", "file-loader": "6.0.0",
"filesize": "4.1.2", "filesize": "6.1.0",
"fuse.js": "3.4.6", "fuse.js": "6.0.4",
"gulp": "4.0.2", "gulp": "4.0.2",
"gulp-cached": "1.1.1", "gulp-cached": "1.1.1",
"gulp-concat": "2.6.1", "gulp-concat": "2.6.1",
@ -74,13 +73,13 @@
"history": "4.10.1", "history": "4.10.1",
"html-webpack-plugin": "3.2.0", "html-webpack-plugin": "3.2.0",
"jdu": "1.0.0", "jdu": "1.0.0",
"jquery": "3.4.1", "jquery": "3.5.1",
"loader-utils": "^1.1.0", "loader-utils": "^2.0.0",
"lodash": "4.17.15", "lodash": "4.17.15",
"mini-css-extract-plugin": "0.8.0", "mini-css-extract-plugin": "0.9.0",
"mobile-detect": "1.4.4", "mobile-detect": "1.4.4",
"moment": "2.24.0", "moment": "2.24.0",
"mousetrap": "1.6.3", "mousetrap": "1.6.5",
"normalize.css": "8.0.1", "normalize.css": "8.0.1",
"optimize-css-assets-webpack-plugin": "5.0.3", "optimize-css-assets-webpack-plugin": "5.0.3",
"postcss-color-function": "4.1.0", "postcss-color-function": "4.1.0",
@ -90,46 +89,44 @@
"postcss-simple-vars": "5.0.2", "postcss-simple-vars": "5.0.2",
"postcss-url": "8.0.0", "postcss-url": "8.0.0",
"prop-types": "15.7.2", "prop-types": "15.7.2",
"qs": "6.9.1", "qs": "6.9.4",
"react": "16.8.6", "react": "16.13.1",
"react-addons-shallow-compare": "15.6.2", "react-addons-shallow-compare": "15.6.2",
"react-async-script": "1.1.1", "react-async-script": "1.1.1",
"react-autosuggest": "9.4.3", "react-autosuggest": "10.0.2",
"react-custom-scrollbars": "4.2.1", "react-custom-scrollbars": "4.2.1",
"react-dnd": "9.5.1", "react-dnd": "10.0.2",
"react-dnd-html5-backend": "9.5.1", "react-dnd-html5-backend": "10.0.2",
"react-document-title": "2.0.3", "react-document-title": "2.0.3",
"react-dom": "16.8.6", "react-dom": "16.13.1",
"react-focus-lock": "2.3.1",
"react-google-recaptcha": "2.0.1", "react-google-recaptcha": "2.0.1",
"react-lazyload": "2.6.5", "react-lazyload": "2.6.7",
"react-measure": "1.4.7", "react-measure": "1.4.7",
"react-popper": "1.3.7", "react-popper": "1.3.7",
"react-redux": "7.1.3", "react-redux": "7.2.0",
"react-router": "5.1.2",
"react-router-dom": "5.1.2", "react-router-dom": "5.1.2",
"react-slider": "1.0.1", "react-slider": "1.0.7",
"react-text-truncate": "0.15.0", "react-text-truncate": "0.16.0",
"react-virtualized": "9.21.1", "react-virtualized": "9.21.1",
"redux": "4.0.4", "redux": "4.0.5",
"redux-actions": "2.6.5", "redux-actions": "2.6.5",
"redux-batched-actions": "0.4.1", "redux-batched-actions": "0.5.0",
"redux-localstorage": "0.4.1", "redux-localstorage": "0.4.1",
"redux-thunk": "2.3.0", "redux-thunk": "2.3.0",
"require-nocache": "1.0.0", "require-nocache": "1.0.0",
"reselect": "4.0.0", "reselect": "4.0.0",
"run-sequence": "2.2.1", "run-sequence": "2.2.1",
"streamqueue": "1.1.2", "streamqueue": "1.1.2",
"style-loader": "1.0.1", "style-loader": "1.2.1",
"stylelint": "13.0.0", "stylelint": "13.5.0",
"stylelint-order": "4.0.0", "stylelint-order": "4.0.0",
"uglifyjs-webpack-plugin": "2.2.0", "url-loader": "4.1.0",
"url-loader": "3.0.0", "webpack": "4.42.1",
"webpack": "4.41.2",
"webpack-stream": "5.2.1", "webpack-stream": "5.2.1",
"worker-loader": "2.0.0" "worker-loader": "2.0.0"
}, },
"devDependencies": {
"@sentry/cli": "1.47.1"
},
"main": "index.js", "main": "index.js",
"browserslist": [ "browserslist": [
">0.25%", ">0.25%",

@ -10,7 +10,7 @@
<ProjectReference Include="..\NzbDrone.SignalR\Lidarr.SignalR.csproj" /> <ProjectReference Include="..\NzbDrone.SignalR\Lidarr.SignalR.csproj" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<PackageReference Include="FluentValidation" Version="8.6.0" /> <PackageReference Include="FluentValidation" Version="8.6.2" />
<PackageReference Include="Ical.Net" Version="4.1.11" /> <PackageReference Include="Ical.Net" Version="4.1.11" />
<PackageReference Include="Nancy" Version="2.0.0" /> <PackageReference Include="Nancy" Version="2.0.0" />
<PackageReference Include="Nancy.Authentication.Basic" Version="2.0.0" /> <PackageReference Include="Nancy.Authentication.Basic" Version="2.0.0" />

@ -3,7 +3,7 @@
<TargetFrameworks>net462;netcoreapp3.1</TargetFrameworks> <TargetFrameworks>net462;netcoreapp3.1</TargetFrameworks>
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>
<PackageReference Include="FluentValidation" Version="8.6.0" /> <PackageReference Include="FluentValidation" Version="8.6.2" />
<PackageReference Include="Nancy" Version="2.0.0" /> <PackageReference Include="Nancy" Version="2.0.0" />
<PackageReference Include="Nancy.Authentication.Basic" Version="2.0.0" /> <PackageReference Include="Nancy.Authentication.Basic" Version="2.0.0" />
<PackageReference Include="Nancy.Authentication.Forms" Version="2.0.0" /> <PackageReference Include="Nancy.Authentication.Forms" Version="2.0.0" />

@ -1,7 +1,8 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<configuration> <configuration>
<packageSources> <packageSources>
<add key="MyFeed" value="https://pkgs.dev.azure.com/Lidarr/Lidarr/_packaging/SQLite/nuget/v3/index.json" /> <add key="nuget.org" value="https://api.nuget.org/v3/index.json" />
<add key="MyFeed" value="https://pkgs.dev.azure.com/Servarr/Servarr/_packaging/SQLite/nuget/v3/index.json" />
<add key="FluentMigrator" value="https://www.myget.org/F/fluent-migrator/api/v3/index.json" /> <add key="FluentMigrator" value="https://www.myget.org/F/fluent-migrator/api/v3/index.json" />
</packageSources> </packageSources>
</configuration> </configuration>

@ -3,14 +3,14 @@
<TargetFrameworks>net462;netcoreapp3.1</TargetFrameworks> <TargetFrameworks>net462;netcoreapp3.1</TargetFrameworks>
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.4.0" /> <PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.6.1" />
<PackageReference Include="NUnit" Version="3.12.0" /> <PackageReference Include="NUnit" Version="3.12.0" />
<PackageReference Include="NUnit3TestAdapter" Version="3.15.1" /> <PackageReference Include="NUnit3TestAdapter" Version="3.16.1" />
<PackageReference Include="NunitXml.TestLogger" Version="2.1.41" /> <PackageReference Include="NunitXml.TestLogger" Version="2.1.41" />
<PackageReference Include="NBuilder" Version="6.0.1" /> <PackageReference Include="NBuilder" Version="6.1.0" />
</ItemGroup> </ItemGroup>
<ItemGroup Condition="'$(TargetFramework)' == 'netcoreapp3.1'"> <ItemGroup Condition="'$(TargetFramework)' == 'netcoreapp3.1'">
<PackageReference Include="coverlet.collector" Version="1.1.0" PrivateAssets="all" /> <PackageReference Include="coverlet.collector" Version="1.2.1" PrivateAssets="all" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<ProjectReference Include="..\NzbDrone.Core\Lidarr.Core.csproj" /> <ProjectReference Include="..\NzbDrone.Core\Lidarr.Core.csproj" />

@ -3,9 +3,9 @@
<TargetFrameworks>net462;netcoreapp3.1</TargetFrameworks> <TargetFrameworks>net462;netcoreapp3.1</TargetFrameworks>
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.4.0" /> <PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.6.1" />
<PackageReference Include="NUnit" Version="3.12.0" /> <PackageReference Include="NUnit" Version="3.12.0" />
<PackageReference Include="NUnit3TestAdapter" Version="3.15.1" /> <PackageReference Include="NUnit3TestAdapter" Version="3.16.1" />
<PackageReference Include="NunitXml.TestLogger" Version="2.1.41" /> <PackageReference Include="NunitXml.TestLogger" Version="2.1.41" />
<PackageReference Include="Selenium.Firefox.WebDriver" Version="0.26.0" /> <PackageReference Include="Selenium.Firefox.WebDriver" Version="0.26.0" />
<PackageReference Include="Selenium.Support" Version="3.141.0" /> <PackageReference Include="Selenium.Support" Version="3.141.0" />

@ -3,13 +3,13 @@
<TargetFrameworks>net462;netcoreapp3.1</TargetFrameworks> <TargetFrameworks>net462;netcoreapp3.1</TargetFrameworks>
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.4.0" /> <PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.6.1" />
<PackageReference Include="NUnit" Version="3.12.0" /> <PackageReference Include="NUnit" Version="3.12.0" />
<PackageReference Include="NUnit3TestAdapter" Version="3.15.1" /> <PackageReference Include="NUnit3TestAdapter" Version="3.16.1" />
<PackageReference Include="NunitXml.TestLogger" Version="2.1.41" /> <PackageReference Include="NunitXml.TestLogger" Version="2.1.41" />
</ItemGroup> </ItemGroup>
<ItemGroup Condition="'$(TargetFramework)' == 'netcoreapp3.1'"> <ItemGroup Condition="'$(TargetFramework)' == 'netcoreapp3.1'">
<PackageReference Include="coverlet.collector" Version="1.1.0" PrivateAssets="all" /> <PackageReference Include="coverlet.collector" Version="1.2.1" PrivateAssets="all" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<ProjectReference Include="..\NzbDrone.Host\Lidarr.Host.csproj" /> <ProjectReference Include="..\NzbDrone.Host\Lidarr.Host.csproj" />

@ -6,17 +6,17 @@
<PackageReference Include="DotNet4.SocksProxy" Version="1.4.0.1" /> <PackageReference Include="DotNet4.SocksProxy" Version="1.4.0.1" />
<PackageReference Include="Newtonsoft.Json" Version="12.0.3" /> <PackageReference Include="Newtonsoft.Json" Version="12.0.3" />
<PackageReference Include="NLog" Version="4.6.8" /> <PackageReference Include="NLog" Version="4.6.8" />
<PackageReference Include="Sentry" Version="1.2.0" /> <PackageReference Include="Sentry" Version="2.1.1" />
<PackageReference Include="SharpZipLib" Version="1.2.0" /> <PackageReference Include="SharpZipLib" Version="1.2.0" />
<PackageReference Include="System.IO.Abstractions" Version="7.0.15" /> <PackageReference Include="System.IO.Abstractions" Version="7.0.15" />
<PackageReference Include="System.ValueTuple" Version="4.5.0" /> <PackageReference Include="System.ValueTuple" Version="4.5.0" />
<PackageReference Include="System.Data.SQLite.Core.Lidarr" Version="1.0.111.0-5" /> <PackageReference Include="System.Data.SQLite.Core.Servarr" Version="1.0.113.0-0" />
</ItemGroup> </ItemGroup>
<ItemGroup Condition="'$(TargetFramework)' == 'netcoreapp3.1'"> <ItemGroup Condition="'$(TargetFramework)' == 'netcoreapp3.1'">
<PackageReference Include="System.Runtime.Loader" Version="4.3.0" /> <PackageReference Include="System.Runtime.Loader" Version="4.3.0" />
<PackageReference Include="System.Configuration.ConfigurationManager" Version="4.7.0" /> <PackageReference Include="System.Configuration.ConfigurationManager" Version="4.7.0" />
<PackageReference Include="System.ServiceProcess.ServiceController" Version="4.7.0" /> <PackageReference Include="System.ServiceProcess.ServiceController" Version="4.7.0" />
<PackageReference Include="Microsoft.Extensions.Hosting.WindowsServices" Version="3.1.0" /> <PackageReference Include="Microsoft.Extensions.Hosting.WindowsServices" Version="3.1.5" />
<PackageReference Include="Microsoft.Win32.Registry" Version="4.7.0" /> <PackageReference Include="Microsoft.Win32.Registry" Version="4.7.0" />
</ItemGroup> </ItemGroup>
<ItemGroup Condition="'$(TargetFramework)' == 'net462'"> <ItemGroup Condition="'$(TargetFramework)' == 'net462'">

@ -3,24 +3,23 @@
<TargetFrameworks>net462;netcoreapp3.1</TargetFrameworks> <TargetFrameworks>net462;netcoreapp3.1</TargetFrameworks>
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.4.0" /> <PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.6.1" />
<PackageReference Include="NUnit" Version="3.12.0" /> <PackageReference Include="NUnit" Version="3.12.0" />
<PackageReference Include="NUnit3TestAdapter" Version="3.15.1" /> <PackageReference Include="NUnit3TestAdapter" Version="3.16.1" />
<PackageReference Include="NunitXml.TestLogger" Version="2.1.41" /> <PackageReference Include="NunitXml.TestLogger" Version="2.1.41" />
<PackageReference Include="System.Buffers" Version="4.5.0" /> <PackageReference Include="NBuilder" Version="6.1.0" />
<PackageReference Include="NBuilder" Version="6.0.1" />
<PackageReference Include="System.IO.Abstractions.TestingHelpers" Version="7.0.15" /> <PackageReference Include="System.IO.Abstractions.TestingHelpers" Version="7.0.15" />
<PackageReference Include="AutoFixture" Version="4.11.0" /> <PackageReference Include="AutoFixture" Version="4.11.0" />
</ItemGroup> </ItemGroup>
<ItemGroup Condition="'$(TargetFramework)' == 'netcoreapp3.1'"> <ItemGroup Condition="'$(TargetFramework)' == 'netcoreapp3.1'">
<PackageReference Include="coverlet.collector" Version="1.1.0" PrivateAssets="all" /> <PackageReference Include="coverlet.collector" Version="1.2.1" PrivateAssets="all" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<ProjectReference Include="..\NzbDrone.Test.Common\Lidarr.Test.Common.csproj" /> <ProjectReference Include="..\NzbDrone.Test.Common\Lidarr.Test.Common.csproj" />
<ProjectReference Include="..\NzbDrone.Core\Lidarr.Core.csproj" /> <ProjectReference Include="..\NzbDrone.Core\Lidarr.Core.csproj" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<RuntimeFiles Include="..\Runtimes\$(RuntimeIdentifier)\*"/> <RuntimeFiles Include="..\Runtimes\$(RuntimeIdentifier)\*" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<Content Include="..\..\Logo\1024.png"> <Content Include="..\..\Logo\1024.png">

@ -206,7 +206,7 @@ namespace NzbDrone.Core.Download
try try
{ {
hash = InfoHash.FromMagnetLink(magnetUrl).ToHex(); hash = MagnetLink.Parse(magnetUrl).InfoHash.ToHex();
} }
catch (FormatException ex) catch (FormatException ex)
{ {

@ -52,7 +52,7 @@ namespace NzbDrone.Core.Indexers
{ {
try try
{ {
return InfoHash.FromMagnetLink(magnetUrl).ToHex(); return MagnetLink.Parse(magnetUrl).InfoHash.ToHex();
} }
catch catch
{ {

@ -3,22 +3,22 @@
<TargetFrameworks>net462;netcoreapp3.1</TargetFrameworks> <TargetFrameworks>net462;netcoreapp3.1</TargetFrameworks>
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>
<PackageReference Include="System.Memory" Version="4.5.3" /> <PackageReference Include="System.Memory" Version="4.5.4" />
<PackageReference Include="Microsoft.Extensions.DependencyInjection" Version="3.1.0" /> <PackageReference Include="Microsoft.Extensions.DependencyInjection" Version="3.1.5" />
<PackageReference Include="Microsoft.Extensions.Logging" Version="3.1.0" /> <PackageReference Include="Microsoft.Extensions.Logging" Version="3.1.5" />
<PackageReference Include="FluentMigrator.Runner" Version="4.0.0-alpha.268" /> <PackageReference Include="FluentMigrator.Runner" Version="4.0.0-alpha.268" />
<PackageReference Include="FluentMigrator.Runner.SQLite" Version="4.0.0-alpha.268" /> <PackageReference Include="FluentMigrator.Runner.SQLite" Version="4.0.0-alpha.268" />
<PackageReference Include="FluentValidation" Version="8.6.0" /> <PackageReference Include="FluentValidation" Version="8.6.2" />
<PackageReference Include="Newtonsoft.Json" Version="12.0.3" /> <PackageReference Include="Newtonsoft.Json" Version="12.0.3" />
<PackageReference Include="NLog" Version="4.6.8" /> <PackageReference Include="NLog" Version="4.6.8" />
<PackageReference Include="RestSharp" Version="106.6.10" /> <PackageReference Include="RestSharp" Version="106.10.1" />
<PackageReference Include="System.IO.Abstractions" Version="7.0.15" /> <PackageReference Include="System.IO.Abstractions" Version="7.0.15" />
<PackageReference Include="TagLibSharp-Lidarr" Version="2.2.0.19" /> <PackageReference Include="TagLibSharp-Lidarr" Version="2.2.0.19" />
<PackageReference Include="Kveer.XmlRPC" Version="1.1.1" /> <PackageReference Include="Kveer.XmlRPC" Version="1.1.1" />
<PackageReference Include="SpotifyAPI.Web" Version="4.2.2" /> <PackageReference Include="SpotifyAPI.Web" Version="4.2.2" />
<PackageReference Include="SixLabors.ImageSharp" Version="1.0.0-beta0007" /> <PackageReference Include="SixLabors.ImageSharp" Version="1.0.0-beta0007" />
<PackageReference Include="Equ" Version="2.2.0" /> <PackageReference Include="Equ" Version="2.2.0" />
<PackageReference Include="MonoTorrent" Version="1.0.11" /> <PackageReference Include="MonoTorrent" Version="1.0.19" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<ProjectReference Include="..\Marr.Data\Marr.Data.csproj" /> <ProjectReference Include="..\Marr.Data\Marr.Data.csproj" />
@ -29,7 +29,7 @@
<Reference Include="System.Web.Extensions" /> <Reference Include="System.Web.Extensions" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<RuntimeFiles Include="..\Runtimes\$(RuntimeIdentifier)\*"/> <RuntimeFiles Include="..\Runtimes\$(RuntimeIdentifier)\*" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<EmbeddedResource Include="..\..\Logo\64.png"> <EmbeddedResource Include="..\..\Logo\64.png">

@ -3,13 +3,13 @@
<TargetFrameworks>net462;netcoreapp3.1</TargetFrameworks> <TargetFrameworks>net462;netcoreapp3.1</TargetFrameworks>
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.4.0" /> <PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.6.1" />
<PackageReference Include="NUnit" Version="3.12.0" /> <PackageReference Include="NUnit" Version="3.12.0" />
<PackageReference Include="NUnit3TestAdapter" Version="3.15.1" /> <PackageReference Include="NUnit3TestAdapter" Version="3.16.1" />
<PackageReference Include="NunitXml.TestLogger" Version="2.1.41" /> <PackageReference Include="NunitXml.TestLogger" Version="2.1.41" />
</ItemGroup> </ItemGroup>
<ItemGroup Condition="'$(TargetFramework)' == 'netcoreapp3.1'"> <ItemGroup Condition="'$(TargetFramework)' == 'netcoreapp3.1'">
<PackageReference Include="coverlet.collector" Version="1.1.0" PrivateAssets="all" /> <PackageReference Include="coverlet.collector" Version="1.2.1" PrivateAssets="all" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<ProjectReference Include="..\NzbDrone.Host\Lidarr.Host.csproj" /> <ProjectReference Include="..\NzbDrone.Host\Lidarr.Host.csproj" />

@ -10,8 +10,8 @@
<PackageReference Include="Microsoft.AspNetCore.Owin" Version="2.2.0" /> <PackageReference Include="Microsoft.AspNetCore.Owin" Version="2.2.0" />
</ItemGroup> </ItemGroup>
<ItemGroup Condition="'$(TargetFramework)' == 'netcoreapp3.1'"> <ItemGroup Condition="'$(TargetFramework)' == 'netcoreapp3.1'">
<PackageReference Include="Microsoft.AspNetCore.Owin" Version="3.1.0" /> <PackageReference Include="Microsoft.AspNetCore.Owin" Version="3.1.5" />
<PackageReference Include="Microsoft.AspNetCore.SignalR.Protocols.NewtonsoftJson" Version="3.1.0" /> <PackageReference Include="Microsoft.AspNetCore.SignalR.Protocols.NewtonsoftJson" Version="3.1.5" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<PackageReference Include="NLog.Extensions.Logging" Version="1.6.1" /> <PackageReference Include="NLog.Extensions.Logging" Version="1.6.1" />

@ -4,16 +4,16 @@
<OutputType>Library</OutputType> <OutputType>Library</OutputType>
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.4.0" /> <PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.6.1" />
<PackageReference Include="NUnit" Version="3.12.0" /> <PackageReference Include="NUnit" Version="3.12.0" />
<PackageReference Include="NUnit3TestAdapter" Version="3.15.1" /> <PackageReference Include="NUnit3TestAdapter" Version="3.16.1" />
<PackageReference Include="NunitXml.TestLogger" Version="2.1.41" /> <PackageReference Include="NunitXml.TestLogger" Version="2.1.41" />
</ItemGroup> </ItemGroup>
<ItemGroup Condition="'$(TargetFramework)' == 'net462'"> <ItemGroup Condition="'$(TargetFramework)' == 'net462'">
<PackageReference Include="Microsoft.AspNetCore.SignalR.Client" Version="1.1.0" /> <PackageReference Include="Microsoft.AspNetCore.SignalR.Client" Version="1.1.0" />
</ItemGroup> </ItemGroup>
<ItemGroup Condition="'$(TargetFramework)' == 'netcoreapp3.1'"> <ItemGroup Condition="'$(TargetFramework)' == 'netcoreapp3.1'">
<PackageReference Include="Microsoft.AspNetCore.SignalR.Client" Version="3.1.0" /> <PackageReference Include="Microsoft.AspNetCore.SignalR.Client" Version="3.1.5" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<ProjectReference Include="..\Lidarr.Api.V1\Lidarr.Api.V1.csproj" /> <ProjectReference Include="..\Lidarr.Api.V1\Lidarr.Api.V1.csproj" />

@ -3,13 +3,13 @@
<TargetFrameworks>net462;netcoreapp3.1</TargetFrameworks> <TargetFrameworks>net462;netcoreapp3.1</TargetFrameworks>
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.4.0" /> <PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.6.1" />
<PackageReference Include="NUnit" Version="3.12.0" /> <PackageReference Include="NUnit" Version="3.12.0" />
<PackageReference Include="NUnit3TestAdapter" Version="3.15.1" /> <PackageReference Include="NUnit3TestAdapter" Version="3.16.1" />
<PackageReference Include="NunitXml.TestLogger" Version="2.1.41" /> <PackageReference Include="NunitXml.TestLogger" Version="2.1.41" />
</ItemGroup> </ItemGroup>
<ItemGroup Condition="'$(TargetFramework)' == 'netcoreapp3.1'"> <ItemGroup Condition="'$(TargetFramework)' == 'netcoreapp3.1'">
<PackageReference Include="coverlet.collector" Version="1.1.0" PrivateAssets="all" /> <PackageReference Include="coverlet.collector" Version="1.2.1" PrivateAssets="all" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<ProjectReference Include="..\NzbDrone.Test.Common\Lidarr.Test.Common.csproj" /> <ProjectReference Include="..\NzbDrone.Test.Common\Lidarr.Test.Common.csproj" />

@ -3,13 +3,13 @@
<TargetFrameworks>net462;netcoreapp3.1</TargetFrameworks> <TargetFrameworks>net462;netcoreapp3.1</TargetFrameworks>
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.4.0" /> <PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.6.1" />
<PackageReference Include="NUnit" Version="3.12.0" /> <PackageReference Include="NUnit" Version="3.12.0" />
<PackageReference Include="NUnit3TestAdapter" Version="3.15.1" /> <PackageReference Include="NUnit3TestAdapter" Version="3.16.1" />
<PackageReference Include="NunitXml.TestLogger" Version="2.1.41" /> <PackageReference Include="NunitXml.TestLogger" Version="2.1.41" />
</ItemGroup> </ItemGroup>
<ItemGroup Condition="'$(TargetFramework)' == 'net462'"> <ItemGroup Condition="'$(TargetFramework)' == 'net462'">
<PackageReference Include="Mono.Posix-4.5" Version="4.5.0" PrivateAssets="all"/> <PackageReference Include="Mono.Posix-4.5" Version="4.5.0" PrivateAssets="all" />
</ItemGroup> </ItemGroup>
<!-- <!--
The netstandard veresion here doesn't work in net framework The netstandard veresion here doesn't work in net framework
@ -17,7 +17,7 @@
--> -->
<ItemGroup Condition="'$(TargetFramework)' == 'netcoreapp3.1'"> <ItemGroup Condition="'$(TargetFramework)' == 'netcoreapp3.1'">
<PackageReference Include="Mono.Posix.NETStandard" Version="1.0.0" /> <PackageReference Include="Mono.Posix.NETStandard" Version="1.0.0" />
<PackageReference Include="coverlet.collector" Version="1.1.0" PrivateAssets="all" /> <PackageReference Include="coverlet.collector" Version="1.2.1" PrivateAssets="all" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<ProjectReference Include="..\NzbDrone.Common.Test\Lidarr.Common.Test.csproj" /> <ProjectReference Include="..\NzbDrone.Common.Test\Lidarr.Common.Test.csproj" />

@ -4,12 +4,12 @@
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>
<PackageReference Include="FluentAssertions" Version="5.9.0" /> <PackageReference Include="FluentAssertions" Version="5.9.0" />
<PackageReference Include="FluentValidation" Version="8.6.0" /> <PackageReference Include="FluentValidation" Version="8.6.2" />
<PackageReference Include="Moq" Version="4.13.1" /> <PackageReference Include="Moq" Version="4.13.1" />
<PackageReference Include="Newtonsoft.Json" Version="12.0.3" /> <PackageReference Include="Newtonsoft.Json" Version="12.0.3" />
<PackageReference Include="NLog" Version="4.6.8" /> <PackageReference Include="NLog" Version="4.6.8" />
<PackageReference Include="NUnit" Version="3.12.0" /> <PackageReference Include="NUnit" Version="3.12.0" />
<PackageReference Include="RestSharp" Version="106.6.10" /> <PackageReference Include="RestSharp" Version="106.10.1" />
<PackageReference Include="System.IO.Abstractions" Version="7.0.15" /> <PackageReference Include="System.IO.Abstractions" Version="7.0.15" />
<PackageReference Include="Unity" Version="5.11.2" /> <PackageReference Include="Unity" Version="5.11.2" />
</ItemGroup> </ItemGroup>

@ -3,13 +3,13 @@
<TargetFrameworks>net462;netcoreapp3.1</TargetFrameworks> <TargetFrameworks>net462;netcoreapp3.1</TargetFrameworks>
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.4.0" /> <PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.6.1" />
<PackageReference Include="NUnit" Version="3.12.0" /> <PackageReference Include="NUnit" Version="3.12.0" />
<PackageReference Include="NUnit3TestAdapter" Version="3.15.1" /> <PackageReference Include="NUnit3TestAdapter" Version="3.16.1" />
<PackageReference Include="NunitXml.TestLogger" Version="2.1.41" /> <PackageReference Include="NunitXml.TestLogger" Version="2.1.41" />
</ItemGroup> </ItemGroup>
<ItemGroup Condition="'$(TargetFramework)' == 'netcoreapp3.1'"> <ItemGroup Condition="'$(TargetFramework)' == 'netcoreapp3.1'">
<PackageReference Include="coverlet.collector" Version="1.1.0" PrivateAssets="all" /> <PackageReference Include="coverlet.collector" Version="1.2.1" PrivateAssets="all" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<ProjectReference Include="..\NzbDrone.Test.Common\Lidarr.Test.Common.csproj" /> <ProjectReference Include="..\NzbDrone.Test.Common\Lidarr.Test.Common.csproj" />

@ -3,13 +3,13 @@
<TargetFrameworks>net462;netcoreapp3.1</TargetFrameworks> <TargetFrameworks>net462;netcoreapp3.1</TargetFrameworks>
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.4.0" /> <PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.6.1" />
<PackageReference Include="NUnit" Version="3.12.0" /> <PackageReference Include="NUnit" Version="3.12.0" />
<PackageReference Include="NUnit3TestAdapter" Version="3.15.1" /> <PackageReference Include="NUnit3TestAdapter" Version="3.16.1" />
<PackageReference Include="NunitXml.TestLogger" Version="2.1.41" /> <PackageReference Include="NunitXml.TestLogger" Version="2.1.41" />
</ItemGroup> </ItemGroup>
<ItemGroup Condition="'$(TargetFramework)' == 'netcoreapp3.1'"> <ItemGroup Condition="'$(TargetFramework)' == 'netcoreapp3.1'">
<PackageReference Include="coverlet.collector" Version="1.1.0" PrivateAssets="all" /> <PackageReference Include="coverlet.collector" Version="1.2.1" PrivateAssets="all" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<ProjectReference Include="..\NzbDrone.Common.Test\Lidarr.Common.Test.csproj" /> <ProjectReference Include="..\NzbDrone.Common.Test\Lidarr.Common.Test.csproj" />

File diff suppressed because it is too large Load Diff
Loading…
Cancel
Save