-
+
\\^$.|?*+()[{ have special meanings and need escaping with a \\
' }} />
+ {'More details'} {'Here'}
-
-
-
-
+ {'Regular expressions can be tested '}
+ Here
}
diff --git a/frontend/src/Settings/DownloadClients/DownloadClients/Manage/ManageDownloadClientsModalContent.tsx b/frontend/src/Settings/DownloadClients/DownloadClients/Manage/ManageDownloadClientsModalContent.tsx
index b2c1208cb..734f5efab 100644
--- a/frontend/src/Settings/DownloadClients/DownloadClients/Manage/ManageDownloadClientsModalContent.tsx
+++ b/frontend/src/Settings/DownloadClients/DownloadClients/Manage/ManageDownloadClientsModalContent.tsx
@@ -10,11 +10,11 @@ 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 Column from 'Components/Table/Column';
import Table from 'Components/Table/Table';
import TableBody from 'Components/Table/TableBody';
import useSelectState from 'Helpers/Hooks/useSelectState';
import { kinds } from 'Helpers/Props';
+import SortDirection from 'Helpers/Props/SortDirection';
import {
bulkDeleteDownloadClients,
bulkEditDownloadClients,
@@ -35,7 +35,7 @@ type OnSelectedChangeCallback = React.ComponentProps<
typeof ManageDownloadClientsModalRow
>['onSelectedChange'];
-const COLUMNS: Column[] = [
+const COLUMNS = [
{
name: 'name',
label: () => translate('Name'),
@@ -82,6 +82,8 @@ const COLUMNS: Column[] = [
interface ManageDownloadClientsModalContentProps {
onModalClose(): void;
+ sortKey?: string;
+ sortDirection?: SortDirection;
}
function ManageDownloadClientsModalContent(
diff --git a/frontend/src/Settings/Indexers/Indexers/Manage/ManageIndexersModalContent.tsx b/frontend/src/Settings/Indexers/Indexers/Manage/ManageIndexersModalContent.tsx
index 997d1b566..dbb394959 100644
--- a/frontend/src/Settings/Indexers/Indexers/Manage/ManageIndexersModalContent.tsx
+++ b/frontend/src/Settings/Indexers/Indexers/Manage/ManageIndexersModalContent.tsx
@@ -10,11 +10,11 @@ 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 Column from 'Components/Table/Column';
import Table from 'Components/Table/Table';
import TableBody from 'Components/Table/TableBody';
import useSelectState from 'Helpers/Hooks/useSelectState';
import { kinds } from 'Helpers/Props';
+import SortDirection from 'Helpers/Props/SortDirection';
import {
bulkDeleteIndexers,
bulkEditIndexers,
@@ -35,7 +35,7 @@ type OnSelectedChangeCallback = React.ComponentProps<
typeof ManageIndexersModalRow
>['onSelectedChange'];
-const COLUMNS: Column[] = [
+const COLUMNS = [
{
name: 'name',
label: () => translate('Name'),
@@ -82,6 +82,8 @@ const COLUMNS: Column[] = [
interface ManageIndexersModalContentProps {
onModalClose(): void;
+ sortKey?: string;
+ sortDirection?: SortDirection;
}
function ManageIndexersModalContent(props: ManageIndexersModalContentProps) {
diff --git a/frontend/src/Settings/MediaManagement/RootFolder/RootFolder.js b/frontend/src/Settings/MediaManagement/RootFolder/RootFolder.js
index dc91e4622..47e5dfcf1 100644
--- a/frontend/src/Settings/MediaManagement/RootFolder/RootFolder.js
+++ b/frontend/src/Settings/MediaManagement/RootFolder/RootFolder.js
@@ -94,9 +94,9 @@ class RootFolder extends Component {
diff --git a/frontend/src/Settings/Quality/Definition/QualityDefinition.css b/frontend/src/Settings/Quality/Definition/QualityDefinition.css
index 860333725..e090428a1 100644
--- a/frontend/src/Settings/Quality/Definition/QualityDefinition.css
+++ b/frontend/src/Settings/Quality/Definition/QualityDefinition.css
@@ -24,19 +24,19 @@
height: 20px;
}
-.track {
+.bar {
top: 9px;
margin: 0 5px;
height: 3px;
background-color: var(--sliderAccentColor);
box-shadow: 0 0 0 #000;
- &:nth-child(3n + 1) {
+ &:nth-child(3n+1) {
background-color: #ddd;
}
}
-.thumb {
+.handle {
top: 1px;
z-index: 0 !important;
width: 18px;
diff --git a/frontend/src/Settings/Quality/Definition/QualityDefinition.css.d.ts b/frontend/src/Settings/Quality/Definition/QualityDefinition.css.d.ts
index 9c9e8393a..2b92fb212 100644
--- a/frontend/src/Settings/Quality/Definition/QualityDefinition.css.d.ts
+++ b/frontend/src/Settings/Quality/Definition/QualityDefinition.css.d.ts
@@ -1,6 +1,8 @@
// This file is automatically generated.
// Please do not change this file!
interface CssExports {
+ 'bar': string;
+ 'handle': string;
'kilobitsPerSecond': string;
'quality': string;
'qualityDefinition': string;
@@ -8,9 +10,7 @@ interface CssExports {
'sizeLimit': string;
'sizes': string;
'slider': string;
- 'thumb': string;
'title': string;
- 'track': string;
}
export const cssExports: CssExports;
export default cssExports;
diff --git a/frontend/src/Settings/Quality/Definition/QualityDefinition.js b/frontend/src/Settings/Quality/Definition/QualityDefinition.js
index 48251abfb..7d8a78737 100644
--- a/frontend/src/Settings/Quality/Definition/QualityDefinition.js
+++ b/frontend/src/Settings/Quality/Definition/QualityDefinition.js
@@ -55,27 +55,6 @@ class QualityDefinition extends Component {
};
}
- //
- // Control
-
- trackRenderer(props, state) {
- return (
-
- );
- }
-
- thumbRenderer(props, state) {
- return (
-
- );
- }
-
//
// Listeners
@@ -195,7 +174,6 @@ class QualityDefinition extends Component {
diff --git a/frontend/src/Settings/Tags/AutoTagging/Specifications/EditSpecificationModalContent.js b/frontend/src/Settings/Tags/AutoTagging/Specifications/EditSpecificationModalContent.js
index 04302729b..2ab1e4a1c 100644
--- a/frontend/src/Settings/Tags/AutoTagging/Specifications/EditSpecificationModalContent.js
+++ b/frontend/src/Settings/Tags/AutoTagging/Specifications/EditSpecificationModalContent.js
@@ -86,10 +86,10 @@ function EditSpecificationModalContent(props) {
-
+
-
+
}
diff --git a/frontend/src/Store/Actions/artistIndexActions.js b/frontend/src/Store/Actions/artistIndexActions.js
index 736502460..055e92662 100644
--- a/frontend/src/Store/Actions/artistIndexActions.js
+++ b/frontend/src/Store/Actions/artistIndexActions.js
@@ -151,7 +151,7 @@ export const defaultState = {
{
name: 'genres',
label: () => translate('Genres'),
- isSortable: true,
+ isSortable: false,
isVisible: false
},
{
diff --git a/frontend/src/Store/Actions/historyActions.js b/frontend/src/Store/Actions/historyActions.js
index 9d16d29c4..225698229 100644
--- a/frontend/src/Store/Actions/historyActions.js
+++ b/frontend/src/Store/Actions/historyActions.js
@@ -150,7 +150,7 @@ export const defaultState = {
},
{
key: 'importFailed',
- label: () => translate('ImportCompleteFailed'),
+ label: () => translate('ImportFailed'),
filters: [
{
key: 'eventType',
diff --git a/frontend/src/Store/Selectors/createArtistAlbumsSelector.ts b/frontend/src/Store/Selectors/createArtistAlbumsSelector.ts
index 414a451f5..baffd87ec 100644
--- a/frontend/src/Store/Selectors/createArtistAlbumsSelector.ts
+++ b/frontend/src/Store/Selectors/createArtistAlbumsSelector.ts
@@ -1,5 +1,4 @@
import { createSelector } from 'reselect';
-import AlbumAppState from 'App/State/AlbumAppState';
import AppState from 'App/State/AppState';
import Artist from 'Artist/Artist';
import { createArtistSelectorForHook } from './createArtistSelector';
@@ -8,7 +7,7 @@ function createArtistAlbumsSelector(artistId: number) {
return createSelector(
(state: AppState) => state.albums,
createArtistSelectorForHook(artistId),
- (albums: AlbumAppState, artist = {} as Artist) => {
+ (albums, artist = {} as Artist) => {
const { isFetching, isPopulated, error, items } = albums;
const filteredAlbums = items.filter(
diff --git a/frontend/src/Store/Selectors/createArtistMetadataProfileSelector.ts b/frontend/src/Store/Selectors/createArtistMetadataProfileSelector.ts
index fa60d936d..0acbd3997 100644
--- a/frontend/src/Store/Selectors/createArtistMetadataProfileSelector.ts
+++ b/frontend/src/Store/Selectors/createArtistMetadataProfileSelector.ts
@@ -1,14 +1,13 @@
import { createSelector } from 'reselect';
import AppState from 'App/State/AppState';
import Artist from 'Artist/Artist';
-import MetadataProfile from 'typings/MetadataProfile';
import { createArtistSelectorForHook } from './createArtistSelector';
function createArtistMetadataProfileSelector(artistId: number) {
return createSelector(
(state: AppState) => state.settings.metadataProfiles.items,
createArtistSelectorForHook(artistId),
- (metadataProfiles: MetadataProfile[], artist = {} as Artist) => {
+ (metadataProfiles, artist = {} as Artist) => {
return metadataProfiles.find((profile) => {
return profile.id === artist.metadataProfileId;
});
diff --git a/frontend/src/Store/Selectors/createArtistQualityProfileSelector.ts b/frontend/src/Store/Selectors/createArtistQualityProfileSelector.ts
index 67639919b..99325276f 100644
--- a/frontend/src/Store/Selectors/createArtistQualityProfileSelector.ts
+++ b/frontend/src/Store/Selectors/createArtistQualityProfileSelector.ts
@@ -1,14 +1,13 @@
import { createSelector } from 'reselect';
import AppState from 'App/State/AppState';
import Artist from 'Artist/Artist';
-import QualityProfile from 'typings/QualityProfile';
import { createArtistSelectorForHook } from './createArtistSelector';
function createArtistQualityProfileSelector(artistId: number) {
return createSelector(
(state: AppState) => state.settings.qualityProfiles.items,
createArtistSelectorForHook(artistId),
- (qualityProfiles: QualityProfile[], artist = {} as Artist) => {
+ (qualityProfiles, artist = {} as Artist) => {
return qualityProfiles.find(
(profile) => profile.id === artist.qualityProfileId
);
diff --git a/frontend/src/System/Logs/Files/LogFiles.js b/frontend/src/System/Logs/Files/LogFiles.js
index 5339a8590..83736c617 100644
--- a/frontend/src/System/Logs/Files/LogFiles.js
+++ b/frontend/src/System/Logs/Files/LogFiles.js
@@ -1,8 +1,8 @@
import PropTypes from 'prop-types';
import React, { Component } from 'react';
import Alert from 'Components/Alert';
+import Link from 'Components/Link/Link';
import LoadingIndicator from 'Components/Loading/LoadingIndicator';
-import InlineMarkdown from 'Components/Markdown/InlineMarkdown';
import PageContent from 'Components/Page/PageContent';
import PageContentBody from 'Components/Page/PageContentBody';
import PageToolbar from 'Components/Page/Toolbar/PageToolbar';
@@ -77,16 +77,15 @@ class LogFiles extends Component {
- {translate('LogFilesLocation', {
- location
- })}
+ Log files are located in: {location}
- {currentLogView === 'Log Files' ? (
-
-
-
- ) : null}
+ {
+ currentLogView === 'Log Files' &&
+
+ The log level defaults to 'Info' and can be changed in General Settings
+
+ }
{
diff --git a/frontend/src/System/Updates/Updates.tsx b/frontend/src/System/Updates/Updates.tsx
index 300ab1f99..ef3d20288 100644
--- a/frontend/src/System/Updates/Updates.tsx
+++ b/frontend/src/System/Updates/Updates.tsx
@@ -270,7 +270,7 @@ function Updates() {
{generalSettingsError ? (
- {translate('FailedToFetchSettings')}
+ {translate('FailedToUpdateSettings')}
) : null}
diff --git a/frontend/src/Utilities/Date/getRelativeDate.ts b/frontend/src/Utilities/Date/getRelativeDate.js
similarity index 65%
rename from frontend/src/Utilities/Date/getRelativeDate.ts
rename to frontend/src/Utilities/Date/getRelativeDate.js
index 178d14fb7..812064272 100644
--- a/frontend/src/Utilities/Date/getRelativeDate.ts
+++ b/frontend/src/Utilities/Date/getRelativeDate.js
@@ -6,33 +6,15 @@ import isTomorrow from 'Utilities/Date/isTomorrow';
import isYesterday from 'Utilities/Date/isYesterday';
import translate from 'Utilities/String/translate';
-interface GetRelativeDateOptions {
- timeFormat?: string;
- includeSeconds?: boolean;
- timeForToday?: boolean;
-}
-
-function getRelativeDate(
- date: string | undefined,
- shortDateFormat: string,
- showRelativeDates: boolean,
- {
- timeFormat,
- includeSeconds = false,
- timeForToday = false,
- }: GetRelativeDateOptions = {}
-) {
+function getRelativeDate(date, shortDateFormat, showRelativeDates, { timeFormat, includeSeconds = false, timeForToday = false } = {}) {
if (!date) {
- return '';
+ return null;
}
const isTodayDate = isToday(date);
if (isTodayDate && timeForToday && timeFormat) {
- return formatTime(date, timeFormat, {
- includeMinuteZero: true,
- includeSeconds,
- });
+ return formatTime(date, timeFormat, { includeMinuteZero: true, includeSeconds });
}
if (!showRelativeDates) {
diff --git a/frontend/src/Utilities/String/translate.ts b/frontend/src/Utilities/String/translate.ts
index 5571ef6b0..98a0418ad 100644
--- a/frontend/src/Utilities/String/translate.ts
+++ b/frontend/src/Utilities/String/translate.ts
@@ -17,7 +17,7 @@ export async function fetchTranslations(): Promise {
translations = data.strings;
resolve(true);
- } catch {
+ } catch (error) {
resolve(false);
}
});
@@ -27,12 +27,6 @@ export default function translate(
key: string,
tokens: Record = {}
) {
- const { isProduction = true } = window.Lidarr;
-
- if (!isProduction && !(key in translations)) {
- console.warn(`Missing translation for key: ${key}`);
- }
-
const translation = translations[key] || key;
tokens.appName = 'Lidarr';
diff --git a/frontend/src/bootstrap.tsx b/frontend/src/bootstrap.tsx
index 9ecf27e0e..6a6d7fc67 100644
--- a/frontend/src/bootstrap.tsx
+++ b/frontend/src/bootstrap.tsx
@@ -1,6 +1,6 @@
import { createBrowserHistory } from 'history';
import React from 'react';
-import { createRoot } from 'react-dom/client';
+import { render } from 'react-dom';
import createAppStore from 'Store/createAppStore';
import App from './App/App';
@@ -9,8 +9,9 @@ import 'Diag/ConsoleApi';
export async function bootstrap() {
const history = createBrowserHistory();
const store = createAppStore(history);
- const container = document.getElementById('root');
- const root = createRoot(container!); // createRoot(container!) if you use TypeScript
- root.render();
+ render(
+ ,
+ document.getElementById('root')
+ );
}
diff --git a/frontend/src/index.ts b/frontend/src/index.ts
index 37e780919..36aed4c4b 100644
--- a/frontend/src/index.ts
+++ b/frontend/src/index.ts
@@ -14,32 +14,6 @@ window.Lidarr = await response.json();
__webpack_public_path__ = `${window.Lidarr.urlBase}/`;
/* eslint-enable no-undef, @typescript-eslint/ban-ts-comment */
-const error = console.error;
-
-// Monkey patch console.error to filter out some warnings from React
-// TODO: Remove this after the great TypeScript migration
-
-// eslint-disable-next-line @typescript-eslint/no-explicit-any
-function logError(...parameters: any[]) {
- const filter = parameters.find((parameter) => {
- return (
- typeof parameter === 'string' &&
- (parameter.includes(
- 'Support for defaultProps will be removed from function components in a future major release'
- ) ||
- parameter.includes(
- 'findDOMNode is deprecated and will be removed in the next major release'
- ))
- );
- });
-
- if (!filter) {
- error(...parameters);
- }
-}
-
-console.error = logError;
-
const { bootstrap } = await import('./bootstrap');
await bootstrap();
diff --git a/frontend/src/typings/inputs.ts b/frontend/src/typings/inputs.ts
index 7d202cd44..c0fda305c 100644
--- a/frontend/src/typings/inputs.ts
+++ b/frontend/src/typings/inputs.ts
@@ -1,10 +1,3 @@
-export type InputChanged = {
- name: string;
- value: T;
-};
-
-export type InputOnChange = (change: InputChanged) => void;
-
export type CheckInputChanged = {
name: string;
value: boolean;
diff --git a/frontend/typings/Globals.d.ts b/frontend/typings/Globals.d.ts
index 3509249fc..b2b10fb70 100644
--- a/frontend/typings/Globals.d.ts
+++ b/frontend/typings/Globals.d.ts
@@ -7,6 +7,5 @@ interface Window {
theme: string;
urlBase: string;
version: string;
- isProduction: boolean;
};
}
diff --git a/package.json b/package.json
index 642d79a12..7f75cf6a1 100644
--- a/package.json
+++ b/package.json
@@ -25,18 +25,18 @@
"defaults"
],
"dependencies": {
- "@fortawesome/fontawesome-free": "6.7.1",
- "@fortawesome/fontawesome-svg-core": "6.7.1",
- "@fortawesome/free-regular-svg-icons": "6.7.1",
- "@fortawesome/free-solid-svg-icons": "6.7.1",
+ "@fortawesome/fontawesome-free": "6.6.0",
+ "@fortawesome/fontawesome-svg-core": "6.6.0",
+ "@fortawesome/free-regular-svg-icons": "6.6.0",
+ "@fortawesome/free-solid-svg-icons": "6.6.0",
"@fortawesome/react-fontawesome": "0.2.2",
"@juggle/resize-observer": "3.4.0",
"@microsoft/signalr": "6.0.25",
"@sentry/browser": "7.119.1",
"@sentry/integrations": "7.119.1",
"@types/node": "20.16.11",
- "@types/react": "18.3.12",
- "@types/react-dom": "18.3.1",
+ "@types/react": "18.2.79",
+ "@types/react-dom": "18.2.25",
"classnames": "2.5.1",
"clipboard": "2.0.11",
"connected-react-router": "6.9.3",
@@ -53,7 +53,7 @@
"normalize.css": "8.0.1",
"prop-types": "15.8.1",
"qs": "6.13.0",
- "react": "18.3.1",
+ "react": "17.0.2",
"react-addons-shallow-compare": "15.6.3",
"react-async-script": "1.2.0",
"react-autosuggest": "10.1.0",
@@ -63,7 +63,7 @@
"react-dnd-multi-backend": "6.0.2",
"react-dnd-touch-backend": "14.1.1",
"react-document-title": "2.0.3",
- "react-dom": "18.3.1",
+ "react-dom": "17.0.2",
"react-focus-lock": "2.9.4",
"react-google-recaptcha": "2.1.0",
"react-lazyload": "3.2.0",
@@ -86,16 +86,16 @@
"redux-thunk": "2.4.2",
"reselect": "4.1.8",
"stacktrace-js": "2.0.2",
- "typescript": "5.7.2"
+ "typescript": "5.1.6"
},
"devDependencies": {
- "@babel/core": "7.26.0",
- "@babel/eslint-parser": "7.25.9",
- "@babel/plugin-proposal-export-default-from": "7.25.9",
+ "@babel/core": "7.25.8",
+ "@babel/eslint-parser": "7.25.8",
+ "@babel/plugin-proposal-export-default-from": "7.25.8",
"@babel/plugin-syntax-dynamic-import": "7.8.3",
- "@babel/preset-env": "7.26.0",
- "@babel/preset-react": "7.26.3",
- "@babel/preset-typescript": "7.26.0",
+ "@babel/preset-env": "7.25.8",
+ "@babel/preset-react": "7.25.7",
+ "@babel/preset-typescript": "7.25.7",
"@types/lodash": "4.14.195",
"@types/react-lazyload": "3.2.3",
"@types/react-router-dom": "5.3.3",
@@ -103,13 +103,13 @@
"@types/react-window": "1.8.8",
"@types/redux-actions": "2.6.5",
"@types/webpack-livereload-plugin": "2.3.6",
- "@typescript-eslint/eslint-plugin": "8.18.1",
- "@typescript-eslint/parser": "8.18.1",
+ "@typescript-eslint/eslint-plugin": "6.21.0",
+ "@typescript-eslint/parser": "6.21.0",
"autoprefixer": "10.4.20",
"babel-loader": "9.2.1",
"babel-plugin-inline-classnames": "2.0.1",
"babel-plugin-transform-react-remove-prop-types": "0.4.24",
- "core-js": "3.41.0",
+ "core-js": "3.38.1",
"css-loader": "6.7.3",
"css-modules-typescript-loader": "4.0.1",
"eslint": "8.57.1",
diff --git a/src/Directory.Build.props b/src/Directory.Build.props
index f9853bdd5..adc1a01b7 100644
--- a/src/Directory.Build.props
+++ b/src/Directory.Build.props
@@ -99,35 +99,6 @@
$(MSBuildProjectName.Replace('Lidarr','NzbDrone'))
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- true
-
-
-
- true
-
- true
-
-
diff --git a/src/Lidarr.Api.V1/Albums/AlbumLookupController.cs b/src/Lidarr.Api.V1/Albums/AlbumLookupController.cs
index e8853f611..cd4e6b54a 100644
--- a/src/Lidarr.Api.V1/Albums/AlbumLookupController.cs
+++ b/src/Lidarr.Api.V1/Albums/AlbumLookupController.cs
@@ -20,8 +20,7 @@ namespace Lidarr.Api.V1.Albums
}
[HttpGet]
- [Produces("application/json")]
- public IEnumerable Search(string term)
+ public object Search(string term)
{
var searchResults = _searchProxy.SearchForNewAlbum(term, null);
return MapToResource(searchResults).ToList();
diff --git a/src/Lidarr.Api.V1/Artist/ArtistLookupController.cs b/src/Lidarr.Api.V1/Artist/ArtistLookupController.cs
index 19a18a0ba..27ff021a1 100644
--- a/src/Lidarr.Api.V1/Artist/ArtistLookupController.cs
+++ b/src/Lidarr.Api.V1/Artist/ArtistLookupController.cs
@@ -23,8 +23,7 @@ namespace Lidarr.Api.V1.Artist
}
[HttpGet]
- [Produces("application/json")]
- public IEnumerable Search([FromQuery] string term)
+ public object Search([FromQuery] string term)
{
var searchResults = _searchProxy.SearchForNewArtist(term);
return MapToResource(searchResults).ToList();
diff --git a/src/Lidarr.Api.V1/Config/HostConfigController.cs b/src/Lidarr.Api.V1/Config/HostConfigController.cs
index 00e705325..9046943e8 100644
--- a/src/Lidarr.Api.V1/Config/HostConfigController.cs
+++ b/src/Lidarr.Api.V1/Config/HostConfigController.cs
@@ -33,6 +33,7 @@ namespace Lidarr.Api.V1.Config
SharedValidator.RuleFor(c => c.BindAddress)
.ValidIpAddress()
+ .NotListenAllIp4Address()
.When(c => c.BindAddress != "*" && c.BindAddress != "localhost");
SharedValidator.RuleFor(c => c.Port).ValidPort();
diff --git a/src/Lidarr.Api.V1/DownloadClient/DownloadClientController.cs b/src/Lidarr.Api.V1/DownloadClient/DownloadClientController.cs
index b1cbb3ab5..bd4c993bf 100644
--- a/src/Lidarr.Api.V1/DownloadClient/DownloadClientController.cs
+++ b/src/Lidarr.Api.V1/DownloadClient/DownloadClientController.cs
@@ -1,7 +1,5 @@
-using FluentValidation;
using Lidarr.Http;
using NzbDrone.Core.Download;
-using NzbDrone.SignalR;
namespace Lidarr.Api.V1.DownloadClient
{
@@ -11,10 +9,9 @@ namespace Lidarr.Api.V1.DownloadClient
public static readonly DownloadClientResourceMapper ResourceMapper = new ();
public static readonly DownloadClientBulkResourceMapper BulkResourceMapper = new ();
- public DownloadClientController(IBroadcastSignalRMessage signalRBroadcaster, IDownloadClientFactory downloadClientFactory)
- : base(signalRBroadcaster, downloadClientFactory, "downloadclient", ResourceMapper, BulkResourceMapper)
+ public DownloadClientController(IDownloadClientFactory downloadClientFactory)
+ : base(downloadClientFactory, "downloadclient", ResourceMapper, BulkResourceMapper)
{
- SharedValidator.RuleFor(c => c.Priority).InclusiveBetween(1, 50);
}
}
}
diff --git a/src/Lidarr.Api.V1/Health/HealthResource.cs b/src/Lidarr.Api.V1/Health/HealthResource.cs
index b059198db..9de525009 100644
--- a/src/Lidarr.Api.V1/Health/HealthResource.cs
+++ b/src/Lidarr.Api.V1/Health/HealthResource.cs
@@ -1,6 +1,7 @@
-using System.Collections.Generic;
+using System.Collections.Generic;
using System.Linq;
using Lidarr.Http.REST;
+using NzbDrone.Common.Http;
using NzbDrone.Core.HealthCheck;
namespace Lidarr.Api.V1.Health
@@ -10,7 +11,7 @@ namespace Lidarr.Api.V1.Health
public string Source { get; set; }
public HealthCheckResult Type { get; set; }
public string Message { get; set; }
- public string WikiUrl { get; set; }
+ public HttpUri WikiUrl { get; set; }
}
public static class HealthResourceMapper
@@ -28,7 +29,7 @@ namespace Lidarr.Api.V1.Health
Source = model.Source.Name,
Type = model.Type,
Message = model.Message,
- WikiUrl = model.WikiUrl.FullUri
+ WikiUrl = model.WikiUrl
};
}
diff --git a/src/Lidarr.Api.V1/ImportLists/ImportListController.cs b/src/Lidarr.Api.V1/ImportLists/ImportListController.cs
index 24a823e58..ff2ed98db 100644
--- a/src/Lidarr.Api.V1/ImportLists/ImportListController.cs
+++ b/src/Lidarr.Api.V1/ImportLists/ImportListController.cs
@@ -3,7 +3,6 @@ using Lidarr.Http;
using NzbDrone.Core.ImportLists;
using NzbDrone.Core.Validation;
using NzbDrone.Core.Validation.Paths;
-using NzbDrone.SignalR;
namespace Lidarr.Api.V1.ImportLists
{
@@ -13,12 +12,11 @@ namespace Lidarr.Api.V1.ImportLists
public static readonly ImportListResourceMapper ResourceMapper = new ();
public static readonly ImportListBulkResourceMapper BulkResourceMapper = new ();
- public ImportListController(IBroadcastSignalRMessage signalRBroadcaster,
- IImportListFactory importListFactory,
- RootFolderExistsValidator rootFolderExistsValidator,
- QualityProfileExistsValidator qualityProfileExistsValidator,
- MetadataProfileExistsValidator metadataProfileExistsValidator)
- : base(signalRBroadcaster, importListFactory, "importlist", ResourceMapper, BulkResourceMapper)
+ public ImportListController(IImportListFactory importListFactory,
+ RootFolderExistsValidator rootFolderExistsValidator,
+ QualityProfileExistsValidator qualityProfileExistsValidator,
+ MetadataProfileExistsValidator metadataProfileExistsValidator)
+ : base(importListFactory, "importlist", ResourceMapper, BulkResourceMapper)
{
SharedValidator.RuleFor(c => c.RootFolderPath).Cascade(CascadeMode.Stop)
.IsValidPath()
diff --git a/src/Lidarr.Api.V1/Indexers/IndexerController.cs b/src/Lidarr.Api.V1/Indexers/IndexerController.cs
index 462c68898..2ebcd3f29 100644
--- a/src/Lidarr.Api.V1/Indexers/IndexerController.cs
+++ b/src/Lidarr.Api.V1/Indexers/IndexerController.cs
@@ -1,8 +1,6 @@
-using FluentValidation;
using Lidarr.Http;
using NzbDrone.Core.Indexers;
using NzbDrone.Core.Validation;
-using NzbDrone.SignalR;
namespace Lidarr.Api.V1.Indexers
{
@@ -12,12 +10,9 @@ namespace Lidarr.Api.V1.Indexers
public static readonly IndexerResourceMapper ResourceMapper = new ();
public static readonly IndexerBulkResourceMapper BulkResourceMapper = new ();
- public IndexerController(IBroadcastSignalRMessage signalRBroadcaster,
- IndexerFactory indexerFactory,
- DownloadClientExistsValidator downloadClientExistsValidator)
- : base(signalRBroadcaster, indexerFactory, "indexer", ResourceMapper, BulkResourceMapper)
+ public IndexerController(IndexerFactory indexerFactory, DownloadClientExistsValidator downloadClientExistsValidator)
+ : base(indexerFactory, "indexer", ResourceMapper, BulkResourceMapper)
{
- SharedValidator.RuleFor(c => c.Priority).InclusiveBetween(1, 50);
SharedValidator.RuleFor(c => c.DownloadClientId).SetValidator(downloadClientExistsValidator);
}
}
diff --git a/src/Lidarr.Api.V1/Lidarr.Api.V1.csproj b/src/Lidarr.Api.V1/Lidarr.Api.V1.csproj
index 187fa86ff..7ad7f394f 100644
--- a/src/Lidarr.Api.V1/Lidarr.Api.V1.csproj
+++ b/src/Lidarr.Api.V1/Lidarr.Api.V1.csproj
@@ -12,8 +12,8 @@
-
-
+
+
diff --git a/src/Lidarr.Api.V1/Metadata/MetadataController.cs b/src/Lidarr.Api.V1/Metadata/MetadataController.cs
index 4349058b0..01e82ad37 100644
--- a/src/Lidarr.Api.V1/Metadata/MetadataController.cs
+++ b/src/Lidarr.Api.V1/Metadata/MetadataController.cs
@@ -2,7 +2,6 @@ using System;
using Lidarr.Http;
using Microsoft.AspNetCore.Mvc;
using NzbDrone.Core.Extras.Metadata;
-using NzbDrone.SignalR;
namespace Lidarr.Api.V1.Metadata
{
@@ -12,8 +11,8 @@ namespace Lidarr.Api.V1.Metadata
public static readonly MetadataResourceMapper ResourceMapper = new ();
public static readonly MetadataBulkResourceMapper BulkResourceMapper = new ();
- public MetadataController(IBroadcastSignalRMessage signalRBroadcaster, IMetadataFactory metadataFactory)
- : base(signalRBroadcaster, metadataFactory, "metadata", ResourceMapper, BulkResourceMapper)
+ public MetadataController(IMetadataFactory metadataFactory)
+ : base(metadataFactory, "metadata", ResourceMapper, BulkResourceMapper)
{
}
diff --git a/src/Lidarr.Api.V1/Notifications/NotificationController.cs b/src/Lidarr.Api.V1/Notifications/NotificationController.cs
index 7e5f45064..dc792fc1f 100644
--- a/src/Lidarr.Api.V1/Notifications/NotificationController.cs
+++ b/src/Lidarr.Api.V1/Notifications/NotificationController.cs
@@ -2,7 +2,6 @@ using System;
using Lidarr.Http;
using Microsoft.AspNetCore.Mvc;
using NzbDrone.Core.Notifications;
-using NzbDrone.SignalR;
namespace Lidarr.Api.V1.Notifications
{
@@ -12,8 +11,8 @@ namespace Lidarr.Api.V1.Notifications
public static readonly NotificationResourceMapper ResourceMapper = new ();
public static readonly NotificationBulkResourceMapper BulkResourceMapper = new ();
- public NotificationController(IBroadcastSignalRMessage signalRBroadcaster, NotificationFactory notificationFactory)
- : base(signalRBroadcaster, notificationFactory, "notification", ResourceMapper, BulkResourceMapper)
+ public NotificationController(NotificationFactory notificationFactory)
+ : base(notificationFactory, "notification", ResourceMapper, BulkResourceMapper)
{
}
diff --git a/src/Lidarr.Api.V1/ProviderControllerBase.cs b/src/Lidarr.Api.V1/ProviderControllerBase.cs
index c630dddd9..8d0b88c4a 100644
--- a/src/Lidarr.Api.V1/ProviderControllerBase.cs
+++ b/src/Lidarr.Api.V1/ProviderControllerBase.cs
@@ -7,19 +7,12 @@ using Lidarr.Http.REST.Attributes;
using Microsoft.AspNetCore.Mvc;
using NzbDrone.Common.Extensions;
using NzbDrone.Common.Serializer;
-using NzbDrone.Core.Datastore.Events;
-using NzbDrone.Core.Messaging.Events;
using NzbDrone.Core.ThingiProvider;
-using NzbDrone.Core.ThingiProvider.Events;
using NzbDrone.Core.Validation;
-using NzbDrone.SignalR;
namespace Lidarr.Api.V1
{
- public abstract class ProviderControllerBase : RestControllerWithSignalR,
- IHandle>,
- IHandle>,
- IHandle>
+ public abstract class ProviderControllerBase : RestController
where TProviderDefinition : ProviderDefinition, new()
where TProvider : IProvider
where TProviderResource : ProviderResource, new()
@@ -29,13 +22,11 @@ namespace Lidarr.Api.V1
private readonly ProviderResourceMapper _resourceMapper;
private readonly ProviderBulkResourceMapper _bulkResourceMapper;
- protected ProviderControllerBase(IBroadcastSignalRMessage signalRBroadcaster,
- IProviderFactory providerFactory,
string resource,
ProviderResourceMapper resourceMapper,
ProviderBulkResourceMapper bulkResourceMapper)
- : base(signalRBroadcaster)
{
_providerFactory = providerFactory;
_resourceMapper = resourceMapper;
@@ -270,24 +261,6 @@ namespace Lidarr.Api.V1
return Content(data.ToJson(), "application/json");
}
- [NonAction]
- public virtual void Handle(ProviderAddedEvent message)
- {
- BroadcastResourceChange(ModelAction.Created, message.Definition.Id);
- }
-
- [NonAction]
- public virtual void Handle(ProviderUpdatedEvent message)
- {
- BroadcastResourceChange(ModelAction.Updated, message.Definition.Id);
- }
-
- [NonAction]
- public virtual void Handle(ProviderDeletedEvent message)
- {
- BroadcastResourceChange(ModelAction.Deleted, message.ProviderId);
- }
-
protected virtual void Validate(TProviderDefinition definition, bool includeWarnings)
{
var validationResult = definition.Settings.Validate();
diff --git a/src/Lidarr.Api.V1/Queue/QueueController.cs b/src/Lidarr.Api.V1/Queue/QueueController.cs
index 8123f30fe..730b50436 100644
--- a/src/Lidarr.Api.V1/Queue/QueueController.cs
+++ b/src/Lidarr.Api.V1/Queue/QueueController.cs
@@ -302,7 +302,7 @@ namespace Lidarr.Api.V1.Queue
if (blocklist)
{
- _failedDownloadService.MarkAsFailed(trackedDownload, skipRedownload);
+ _failedDownloadService.MarkAsFailed(trackedDownload.DownloadItem.DownloadId, skipRedownload);
}
if (!removeFromClient && !blocklist && !changeCategory)
diff --git a/src/Lidarr.Api.V1/RemotePathMappings/RemotePathMappingController.cs b/src/Lidarr.Api.V1/RemotePathMappings/RemotePathMappingController.cs
index fae5b2388..f0679e27b 100644
--- a/src/Lidarr.Api.V1/RemotePathMappings/RemotePathMappingController.cs
+++ b/src/Lidarr.Api.V1/RemotePathMappings/RemotePathMappingController.cs
@@ -4,7 +4,6 @@ using Lidarr.Http;
using Lidarr.Http.REST;
using Lidarr.Http.REST.Attributes;
using Microsoft.AspNetCore.Mvc;
-using NzbDrone.Common.Extensions;
using NzbDrone.Core.RemotePathMappings;
using NzbDrone.Core.Validation.Paths;
@@ -22,28 +21,17 @@ namespace Lidarr.Api.V1.RemotePathMappings
_remotePathMappingService = remotePathMappingService;
SharedValidator.RuleFor(c => c.Host)
- .NotEmpty();
+ .NotEmpty();
// We cannot use IsValidPath here, because it's a remote path, possibly other OS.
SharedValidator.RuleFor(c => c.RemotePath)
- .NotEmpty();
-
- SharedValidator.RuleFor(c => c.RemotePath)
- .Must(remotePath => remotePath.IsNotNullOrWhiteSpace() && !remotePath.StartsWith(" "))
- .WithMessage("Remote Path '{PropertyValue}' must not start with a space");
-
- SharedValidator.RuleFor(c => c.RemotePath)
- .Must(remotePath => remotePath.IsNotNullOrWhiteSpace() && !remotePath.EndsWith(" "))
- .WithMessage("Remote Path '{PropertyValue}' must not end with a space");
+ .NotEmpty();
SharedValidator.RuleFor(c => c.LocalPath)
- .Cascade(CascadeMode.Stop)
- .IsValidPath()
- .SetValidator(mappedNetworkDriveValidator)
- .SetValidator(pathExistsValidator)
- .SetValidator(new SystemFolderValidator())
- .NotEqual("/")
- .WithMessage("Cannot be set to '/'");
+ .Cascade(CascadeMode.Stop)
+ .IsValidPath()
+ .SetValidator(mappedNetworkDriveValidator)
+ .SetValidator(pathExistsValidator);
}
public override RemotePathMappingResource GetResourceById(int id)
@@ -53,7 +41,7 @@ namespace Lidarr.Api.V1.RemotePathMappings
[RestPostById]
[Consumes("application/json")]
- public ActionResult CreateMapping([FromBody] RemotePathMappingResource resource)
+ public ActionResult CreateMapping(RemotePathMappingResource resource)
{
var model = resource.ToModel();
@@ -74,7 +62,7 @@ namespace Lidarr.Api.V1.RemotePathMappings
}
[RestPutById]
- public ActionResult UpdateMapping([FromBody] RemotePathMappingResource resource)
+ public ActionResult UpdateMapping(RemotePathMappingResource resource)
{
var mapping = resource.ToModel();
diff --git a/src/Lidarr.Api.V1/Search/SearchController.cs b/src/Lidarr.Api.V1/Search/SearchController.cs
index 220afa064..9dc33066c 100644
--- a/src/Lidarr.Api.V1/Search/SearchController.cs
+++ b/src/Lidarr.Api.V1/Search/SearchController.cs
@@ -24,8 +24,7 @@ namespace Lidarr.Api.V1.Search
}
[HttpGet]
- [Produces("application/json")]
- public IEnumerable Search([FromQuery] string term)
+ public object Search([FromQuery] string term)
{
var searchResults = _searchProxy.SearchForNewEntity(term);
return MapToResource(searchResults).ToList();
diff --git a/src/Lidarr.Api.V1/System/Backup/BackupController.cs b/src/Lidarr.Api.V1/System/Backup/BackupController.cs
index 350ada72b..fba675267 100644
--- a/src/Lidarr.Api.V1/System/Backup/BackupController.cs
+++ b/src/Lidarr.Api.V1/System/Backup/BackupController.cs
@@ -50,7 +50,7 @@ namespace Lidarr.Api.V1.System.Backup
}
[RestDeleteById]
- public object DeleteBackup(int id)
+ public void DeleteBackup(int id)
{
var backup = GetBackup(id);
@@ -67,8 +67,6 @@ namespace Lidarr.Api.V1.System.Backup
}
_diskProvider.DeleteFile(path);
-
- return new { };
}
[HttpPost("restore/{id:int}")]
@@ -92,7 +90,7 @@ namespace Lidarr.Api.V1.System.Backup
}
[HttpPost("restore/upload")]
- [RequestFormLimits(MultipartBodyLengthLimit = 5000000000)]
+ [RequestFormLimits(MultipartBodyLengthLimit = 1000000000)]
public object UploadAndRestore()
{
var files = Request.Form.Files;
diff --git a/src/Lidarr.Api.V1/Tags/TagController.cs b/src/Lidarr.Api.V1/Tags/TagController.cs
index 14f1aef64..a0e76335e 100644
--- a/src/Lidarr.Api.V1/Tags/TagController.cs
+++ b/src/Lidarr.Api.V1/Tags/TagController.cs
@@ -1,5 +1,4 @@
using System.Collections.Generic;
-using FluentValidation;
using Lidarr.Http;
using Lidarr.Http.REST;
using Lidarr.Http.REST.Attributes;
@@ -24,8 +23,6 @@ namespace Lidarr.Api.V1.Tags
: base(signalRBroadcaster)
{
_tagService = tagService;
-
- SharedValidator.RuleFor(c => c.Label).NotEmpty();
}
public override TagResource GetResourceById(int id)
diff --git a/src/Lidarr.Api.V1/openapi.json b/src/Lidarr.Api.V1/openapi.json
index 4c0462717..51bf02eaa 100644
--- a/src/Lidarr.Api.V1/openapi.json
+++ b/src/Lidarr.Api.V1/openapi.json
@@ -327,17 +327,7 @@
],
"responses": {
"200": {
- "description": "OK",
- "content": {
- "application/json": {
- "schema": {
- "type": "array",
- "items": {
- "$ref": "#/components/schemas/AlbumResource"
- }
- }
- }
- }
+ "description": "OK"
}
}
}
@@ -630,17 +620,7 @@
],
"responses": {
"200": {
- "description": "OK",
- "content": {
- "application/json": {
- "schema": {
- "type": "array",
- "items": {
- "$ref": "#/components/schemas/ArtistResource"
- }
- }
- }
- }
+ "description": "OK"
}
}
}
@@ -7312,17 +7292,7 @@
],
"responses": {
"200": {
- "description": "OK",
- "content": {
- "application/json": {
- "schema": {
- "type": "array",
- "items": {
- "$ref": "#/components/schemas/SearchResource"
- }
- }
- }
- }
+ "description": "OK"
}
}
}
@@ -9808,8 +9778,7 @@
"nullable": true
},
"wikiUrl": {
- "type": "string",
- "nullable": true
+ "$ref": "#/components/schemas/HttpUri"
}
},
"additionalProperties": false
@@ -10056,9 +10025,48 @@
"backupRetention": {
"type": "integer",
"format": "int32"
+ }
+ },
+ "additionalProperties": false
+ },
+ "HttpUri": {
+ "type": "object",
+ "properties": {
+ "fullUri": {
+ "type": "string",
+ "nullable": true,
+ "readOnly": true
},
- "trustCgnatIpAddresses": {
- "type": "boolean"
+ "scheme": {
+ "type": "string",
+ "nullable": true,
+ "readOnly": true
+ },
+ "host": {
+ "type": "string",
+ "nullable": true,
+ "readOnly": true
+ },
+ "port": {
+ "type": "integer",
+ "format": "int32",
+ "nullable": true,
+ "readOnly": true
+ },
+ "path": {
+ "type": "string",
+ "nullable": true,
+ "readOnly": true
+ },
+ "query": {
+ "type": "string",
+ "nullable": true,
+ "readOnly": true
+ },
+ "fragment": {
+ "type": "string",
+ "nullable": true,
+ "readOnly": true
}
},
"additionalProperties": false
@@ -12386,26 +12394,6 @@
],
"type": "string"
},
- "SearchResource": {
- "type": "object",
- "properties": {
- "id": {
- "type": "integer",
- "format": "int32"
- },
- "foreignId": {
- "type": "string",
- "nullable": true
- },
- "artist": {
- "$ref": "#/components/schemas/ArtistResource"
- },
- "album": {
- "$ref": "#/components/schemas/AlbumResource"
- }
- },
- "additionalProperties": false
- },
"SecondaryAlbumType": {
"type": "object",
"properties": {
@@ -12881,7 +12869,6 @@
"downloading",
"downloadFailed",
"downloadFailedPending",
- "importBlocked",
"importPending",
"importing",
"importFailed",
diff --git a/src/Lidarr.Http/Authentication/AuthenticationController.cs b/src/Lidarr.Http/Authentication/AuthenticationController.cs
index f7281cf5c..2fc588dd2 100644
--- a/src/Lidarr.Http/Authentication/AuthenticationController.cs
+++ b/src/Lidarr.Http/Authentication/AuthenticationController.cs
@@ -1,14 +1,9 @@
using System.Collections.Generic;
-using System.IO;
using System.Security.Claims;
-using System.Security.Cryptography;
using System.Threading.Tasks;
-using System.Xml;
using Microsoft.AspNetCore.Authentication;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
-using NLog;
-using NzbDrone.Common.EnvironmentInfo;
using NzbDrone.Common.Extensions;
using NzbDrone.Core.Authentication;
using NzbDrone.Core.Configuration;
@@ -21,15 +16,11 @@ namespace Lidarr.Http.Authentication
{
private readonly IAuthenticationService _authService;
private readonly IConfigFileProvider _configFileProvider;
- private readonly IAppFolderInfo _appFolderInfo;
- private readonly Logger _logger;
- public AuthenticationController(IAuthenticationService authService, IConfigFileProvider configFileProvider, IAppFolderInfo appFolderInfo, Logger logger)
+ public AuthenticationController(IAuthenticationService authService, IConfigFileProvider configFileProvider)
{
_authService = authService;
_configFileProvider = configFileProvider;
- _appFolderInfo = appFolderInfo;
- _logger = logger;
}
[HttpPost("login")]
@@ -54,23 +45,7 @@ namespace Lidarr.Http.Authentication
IsPersistent = resource.RememberMe == "on"
};
- try
- {
- await HttpContext.SignInAsync(AuthenticationType.Forms.ToString(), new ClaimsPrincipal(new ClaimsIdentity(claims, "Cookies", "user", "identifier")), authProperties);
- }
- catch (CryptographicException e)
- {
- if (e.InnerException is XmlException)
- {
- _logger.Error(e, "Failed to authenticate user due to corrupt XML. Please remove all XML files from {0} and restart Lidarr", Path.Combine(_appFolderInfo.AppDataFolder, "asp"));
- }
- else
- {
- _logger.Error(e, "Failed to authenticate user. {0}", e.Message);
- }
-
- return Unauthorized();
- }
+ await HttpContext.SignInAsync(AuthenticationType.Forms.ToString(), new ClaimsPrincipal(new ClaimsIdentity(claims, "Cookies", "user", "identifier")), authProperties);
if (returnUrl.IsNullOrWhiteSpace() || !Url.IsLocalUrl(returnUrl))
{
diff --git a/src/Lidarr.Http/Authentication/AuthenticationService.cs b/src/Lidarr.Http/Authentication/AuthenticationService.cs
index d01cd9911..64dd0f323 100644
--- a/src/Lidarr.Http/Authentication/AuthenticationService.cs
+++ b/src/Lidarr.Http/Authentication/AuthenticationService.cs
@@ -77,7 +77,7 @@ namespace Lidarr.Http.Authentication
private void LogSuccess(HttpRequest context, string username)
{
- _authLogger.Debug("Auth-Success ip {0} username '{1}'", context.GetRemoteIP(), username);
+ _authLogger.Info("Auth-Success ip {0} username '{1}'", context.GetRemoteIP(), username);
}
private void LogLogout(HttpRequest context, string username)
diff --git a/src/Lidarr.Http/Lidarr.Http.csproj b/src/Lidarr.Http/Lidarr.Http.csproj
index 103ca71ea..180b3d08f 100644
--- a/src/Lidarr.Http/Lidarr.Http.csproj
+++ b/src/Lidarr.Http/Lidarr.Http.csproj
@@ -5,7 +5,7 @@
-
+
diff --git a/src/NzbDrone.Automation.Test/AutomationTest.cs b/src/NzbDrone.Automation.Test/AutomationTest.cs
index 51c79539e..bcf777431 100644
--- a/src/NzbDrone.Automation.Test/AutomationTest.cs
+++ b/src/NzbDrone.Automation.Test/AutomationTest.cs
@@ -40,16 +40,15 @@ namespace NzbDrone.Automation.Test
var service = ChromeDriverService.CreateDefaultService();
// Timeout as windows automation tests seem to take alot longer to get going
- driver = new ChromeDriver(service, options, TimeSpan.FromMinutes(3));
+ driver = new ChromeDriver(service, options, new TimeSpan(0, 3, 0));
driver.Manage().Window.Size = new System.Drawing.Size(1920, 1080);
- driver.Manage().Window.FullScreen();
_runner = new NzbDroneRunner(LogManager.GetCurrentClassLogger(), null);
_runner.KillAll();
_runner.Start(true);
- driver.Navigate().GoToUrl("http://localhost:8686");
+ driver.Url = "http://localhost:8686";
var page = new PageBase(driver);
page.WaitForNoSpinner();
@@ -69,7 +68,7 @@ namespace NzbDrone.Automation.Test
{
try
{
- var image = (driver as ITakesScreenshot).GetScreenshot();
+ var image = ((ITakesScreenshot)driver).GetScreenshot();
image.SaveAsFile($"./{name}_test_screenshot.png", ScreenshotImageFormat.Png);
}
catch (Exception ex)
diff --git a/src/NzbDrone.Automation.Test/Lidarr.Automation.Test.csproj b/src/NzbDrone.Automation.Test/Lidarr.Automation.Test.csproj
index 8204721f3..ada550253 100644
--- a/src/NzbDrone.Automation.Test/Lidarr.Automation.Test.csproj
+++ b/src/NzbDrone.Automation.Test/Lidarr.Automation.Test.csproj
@@ -4,7 +4,7 @@
-
+
diff --git a/src/NzbDrone.Automation.Test/PageModel/PageBase.cs b/src/NzbDrone.Automation.Test/PageModel/PageBase.cs
index 664ec7258..c9a7e8891 100644
--- a/src/NzbDrone.Automation.Test/PageModel/PageBase.cs
+++ b/src/NzbDrone.Automation.Test/PageModel/PageBase.cs
@@ -1,17 +1,19 @@
using System;
using System.Threading;
using OpenQA.Selenium;
+using OpenQA.Selenium.Remote;
using OpenQA.Selenium.Support.UI;
namespace NzbDrone.Automation.Test.PageModel
{
public class PageBase
{
- private readonly IWebDriver _driver;
+ private readonly RemoteWebDriver _driver;
- public PageBase(IWebDriver driver)
+ public PageBase(RemoteWebDriver driver)
{
_driver = driver;
+ driver.Manage().Window.Maximize();
}
public IWebElement FindByClass(string className, int timeout = 5)
diff --git a/src/NzbDrone.Common.Test/InstrumentationTests/SentryTargetFixture.cs b/src/NzbDrone.Common.Test/InstrumentationTests/SentryTargetFixture.cs
index 2c730bd93..a2400c55b 100644
--- a/src/NzbDrone.Common.Test/InstrumentationTests/SentryTargetFixture.cs
+++ b/src/NzbDrone.Common.Test/InstrumentationTests/SentryTargetFixture.cs
@@ -4,7 +4,6 @@ using System.Linq;
using FluentAssertions;
using NLog;
using NUnit.Framework;
-using NzbDrone.Common.EnvironmentInfo;
using NzbDrone.Common.Instrumentation.Sentry;
using NzbDrone.Test.Common;
@@ -28,7 +27,7 @@ namespace NzbDrone.Common.Test.InstrumentationTests
[SetUp]
public void Setup()
{
- _subject = new SentryTarget("https://aaaaaaaaaaaaaaaaaaaaaaaaaa@sentry.io/111111", Mocker.GetMock().Object);
+ _subject = new SentryTarget("https://aaaaaaaaaaaaaaaaaaaaaaaaaa@sentry.io/111111");
}
private LogEventInfo GivenLogEvent(LogLevel level, Exception ex, string message)
diff --git a/src/NzbDrone.Common/ArchiveService.cs b/src/NzbDrone.Common/ArchiveService.cs
index d420bbbc0..800d240ab 100644
--- a/src/NzbDrone.Common/ArchiveService.cs
+++ b/src/NzbDrone.Common/ArchiveService.cs
@@ -42,18 +42,17 @@ namespace NzbDrone.Common
public void CreateZip(string path, IEnumerable files)
{
- _logger.Debug("Creating archive {0}", path);
-
- using var zipFile = ZipFile.Create(path);
-
- zipFile.BeginUpdate();
-
- foreach (var file in files)
+ using (var zipFile = ZipFile.Create(path))
{
- zipFile.Add(file, Path.GetFileName(file));
- }
+ zipFile.BeginUpdate();
- zipFile.CommitUpdate();
+ foreach (var file in files)
+ {
+ zipFile.Add(file, Path.GetFileName(file));
+ }
+
+ zipFile.CommitUpdate();
+ }
}
private void ExtractZip(string compressedFile, string destination)
diff --git a/src/NzbDrone.Common/Disk/DiskProviderBase.cs b/src/NzbDrone.Common/Disk/DiskProviderBase.cs
index 01aaaaded..dfdb6b54c 100644
--- a/src/NzbDrone.Common/Disk/DiskProviderBase.cs
+++ b/src/NzbDrone.Common/Disk/DiskProviderBase.cs
@@ -3,7 +3,6 @@ using System.Collections.Generic;
using System.IO;
using System.IO.Abstractions;
using System.Linq;
-using System.Threading;
using NLog;
using NzbDrone.Common.EnsureThat;
using NzbDrone.Common.EnvironmentInfo;
@@ -307,26 +306,9 @@ namespace NzbDrone.Common.Disk
{
Ensure.That(path, () => path).IsValidPath(PathValidationType.CurrentOs);
- var files = GetFiles(path, recursive).ToList();
+ var files = GetFiles(path, recursive);
- files.ForEach(RemoveReadOnly);
-
- var attempts = 0;
-
- while (attempts < 3 && files.Any())
- {
- EmptyFolder(path);
-
- if (GetFiles(path, recursive).Any())
- {
- // Wait for IO operations to complete after emptying the folder since they aren't always
- // instantly removed and it can lead to false positives that files are still present.
- Thread.Sleep(3000);
- }
-
- attempts++;
- files = GetFiles(path, recursive).ToList();
- }
+ files.ToList().ForEach(RemoveReadOnly);
_fileSystem.Directory.Delete(path, recursive);
}
diff --git a/src/NzbDrone.Common/Disk/DiskTransferService.cs b/src/NzbDrone.Common/Disk/DiskTransferService.cs
index c0c506c09..9bfb5a7c1 100644
--- a/src/NzbDrone.Common/Disk/DiskTransferService.cs
+++ b/src/NzbDrone.Common/Disk/DiskTransferService.cs
@@ -21,7 +21,7 @@ namespace NzbDrone.Common.Disk
private readonly IDiskProvider _diskProvider;
private readonly Logger _logger;
- private static readonly string[] ReflinkFilesystems = { "btrfs", "xfs", "zfs" };
+ private static readonly string[] _reflinkFilesystems = { "btrfs", "xfs" };
public DiskTransferService(IDiskProvider diskProvider, Logger logger)
{
@@ -343,7 +343,7 @@ namespace NzbDrone.Common.Disk
var targetDriveFormat = targetMount?.DriveFormat ?? string.Empty;
var isCifs = targetDriveFormat == "cifs";
- var tryReflink = sourceDriveFormat == targetDriveFormat && ReflinkFilesystems.Contains(sourceDriveFormat);
+ var tryReflink = sourceDriveFormat == targetDriveFormat && _reflinkFilesystems.Contains(sourceDriveFormat);
if (mode.HasFlag(TransferMode.Copy))
{
diff --git a/src/NzbDrone.Common/Disk/FileSystemLookupService.cs b/src/NzbDrone.Common/Disk/FileSystemLookupService.cs
index be32f7638..427c4237e 100644
--- a/src/NzbDrone.Common/Disk/FileSystemLookupService.cs
+++ b/src/NzbDrone.Common/Disk/FileSystemLookupService.cs
@@ -17,6 +17,37 @@ namespace NzbDrone.Common.Disk
private readonly IDiskProvider _diskProvider;
private readonly IRuntimeInfo _runtimeInfo;
+ private readonly HashSet _setToRemove = new HashSet
+ {
+ // Windows
+ "boot",
+ "bootmgr",
+ "cache",
+ "msocache",
+ "recovery",
+ "$recycle.bin",
+ "recycler",
+ "system volume information",
+ "temporary internet files",
+ "windows",
+
+ // OS X
+ ".fseventd",
+ ".spotlight",
+ ".trashes",
+ ".vol",
+ "cachedmessages",
+ "caches",
+ "trash",
+
+ // QNAP
+ ".@__thumb",
+
+ // Synology
+ "@eadir",
+ "#recycle"
+ };
+
public FileSystemLookupService(IDiskProvider diskProvider, IRuntimeInfo runtimeInfo)
{
_diskProvider = diskProvider;
@@ -127,7 +158,7 @@ namespace NzbDrone.Common.Disk
})
.ToList();
- directories.RemoveAll(d => SpecialFolders.IsSpecialFolder(d.Name));
+ directories.RemoveAll(d => _setToRemove.Contains(d.Name.ToLowerInvariant()));
return directories;
}
diff --git a/src/NzbDrone.Common/Disk/SpecialFolders.cs b/src/NzbDrone.Common/Disk/SpecialFolders.cs
deleted file mode 100644
index b1339a7ed..000000000
--- a/src/NzbDrone.Common/Disk/SpecialFolders.cs
+++ /dev/null
@@ -1,47 +0,0 @@
-using System.Collections.Generic;
-
-namespace NzbDrone.Common.Disk;
-
-public static class SpecialFolders
-{
- private static readonly HashSet _specialFolders = new HashSet
- {
- // Windows
- "boot",
- "bootmgr",
- "cache",
- "msocache",
- "recovery",
- "$recycle.bin",
- "recycler",
- "system volume information",
- "temporary internet files",
- "windows",
-
- // OS X
- ".fseventd",
- ".spotlight",
- ".trashes",
- ".vol",
- "cachedmessages",
- "caches",
- "trash",
-
- // QNAP
- ".@__thumb",
-
- // Synology
- "@eadir",
- "#recycle"
- };
-
- public static bool IsSpecialFolder(string folder)
- {
- if (folder == null)
- {
- return false;
- }
-
- return _specialFolders.Contains(folder.ToLowerInvariant());
- }
-}
diff --git a/src/NzbDrone.Common/Http/Dispatchers/ManagedHttpDispatcher.cs b/src/NzbDrone.Common/Http/Dispatchers/ManagedHttpDispatcher.cs
index 9d896d15c..8ca01f6ec 100644
--- a/src/NzbDrone.Common/Http/Dispatchers/ManagedHttpDispatcher.cs
+++ b/src/NzbDrone.Common/Http/Dispatchers/ManagedHttpDispatcher.cs
@@ -141,7 +141,7 @@ namespace NzbDrone.Common.Http.Dispatchers
}
catch (OperationCanceledException ex) when (cts.IsCancellationRequested)
{
- throw new WebException("Http request timed out", ex, WebExceptionStatus.Timeout, null);
+ throw new WebException("Http request timed out", ex.InnerException, WebExceptionStatus.Timeout, null);
}
}
diff --git a/src/NzbDrone.Common/Instrumentation/CleansingClefLogLayout.cs b/src/NzbDrone.Common/Instrumentation/CleansingClefLogLayout.cs
deleted file mode 100644
index f110b96ac..000000000
--- a/src/NzbDrone.Common/Instrumentation/CleansingClefLogLayout.cs
+++ /dev/null
@@ -1,21 +0,0 @@
-using System.Text;
-using NLog;
-using NLog.Layouts.ClefJsonLayout;
-using NzbDrone.Common.EnvironmentInfo;
-
-namespace NzbDrone.Common.Instrumentation;
-
-public class CleansingClefLogLayout : CompactJsonLayout
-{
- protected override void RenderFormattedMessage(LogEventInfo logEvent, StringBuilder target)
- {
- base.RenderFormattedMessage(logEvent, target);
-
- if (RuntimeInfo.IsProduction)
- {
- var result = CleanseLogMessage.Cleanse(target.ToString());
- target.Clear();
- target.Append(result);
- }
- }
-}
diff --git a/src/NzbDrone.Common/Instrumentation/CleansingConsoleLogLayout.cs b/src/NzbDrone.Common/Instrumentation/CleansingConsoleLogLayout.cs
deleted file mode 100644
index f894a4df5..000000000
--- a/src/NzbDrone.Common/Instrumentation/CleansingConsoleLogLayout.cs
+++ /dev/null
@@ -1,26 +0,0 @@
-using System.Text;
-using NLog;
-using NLog.Layouts;
-using NzbDrone.Common.EnvironmentInfo;
-
-namespace NzbDrone.Common.Instrumentation;
-
-public class CleansingConsoleLogLayout : SimpleLayout
-{
- public CleansingConsoleLogLayout(string format)
- : base(format)
- {
- }
-
- protected override void RenderFormattedMessage(LogEventInfo logEvent, StringBuilder target)
- {
- base.RenderFormattedMessage(logEvent, target);
-
- if (RuntimeInfo.IsProduction)
- {
- var result = CleanseLogMessage.Cleanse(target.ToString());
- target.Clear();
- target.Append(result);
- }
- }
-}
diff --git a/src/NzbDrone.Common/Instrumentation/CleansingFileTarget.cs b/src/NzbDrone.Common/Instrumentation/NzbDroneFileTarget.cs
similarity index 87%
rename from src/NzbDrone.Common/Instrumentation/CleansingFileTarget.cs
rename to src/NzbDrone.Common/Instrumentation/NzbDroneFileTarget.cs
index f74d1fca4..84658cf74 100644
--- a/src/NzbDrone.Common/Instrumentation/CleansingFileTarget.cs
+++ b/src/NzbDrone.Common/Instrumentation/NzbDroneFileTarget.cs
@@ -4,7 +4,7 @@ using NLog.Targets;
namespace NzbDrone.Common.Instrumentation
{
- public class CleansingFileTarget : FileTarget
+ public class NzbDroneFileTarget : FileTarget
{
protected override void RenderFormattedMessage(LogEventInfo logEvent, StringBuilder target)
{
diff --git a/src/NzbDrone.Common/Instrumentation/NzbDroneLogger.cs b/src/NzbDrone.Common/Instrumentation/NzbDroneLogger.cs
index c33211019..74883c959 100644
--- a/src/NzbDrone.Common/Instrumentation/NzbDroneLogger.cs
+++ b/src/NzbDrone.Common/Instrumentation/NzbDroneLogger.cs
@@ -3,6 +3,7 @@ using System.Diagnostics;
using System.IO;
using NLog;
using NLog.Config;
+using NLog.Layouts.ClefJsonLayout;
using NLog.Targets;
using NzbDrone.Common.EnvironmentInfo;
using NzbDrone.Common.Extensions;
@@ -12,11 +13,9 @@ namespace NzbDrone.Common.Instrumentation
{
public static class NzbDroneLogger
{
- private const string FileLogLayout = @"${date:format=yyyy-MM-dd HH\:mm\:ss.f}|${level}|${logger}|${message}${onexception:inner=${newline}${newline}[v${assembly-version}] ${exception:format=ToString}${newline}${exception:format=Data}${newline}}";
- private const string ConsoleFormat = "[${level}] ${logger}: ${message} ${onexception:inner=${newline}${newline}[v${assembly-version}] ${exception:format=ToString}${newline}${exception:format=Data}${newline}}";
-
- private static readonly CleansingConsoleLogLayout CleansingConsoleLayout = new (ConsoleFormat);
- private static readonly CleansingClefLogLayout ClefLogLayout = new ();
+ private const string FILE_LOG_LAYOUT = @"${date:format=yyyy-MM-dd HH\:mm\:ss.f}|${level}|${logger}|${message}${onexception:inner=${newline}${newline}[v${assembly-version}] ${exception:format=ToString}${newline}${exception:format=Data}${newline}}";
+ public const string ConsoleLogLayout = "[${level}] ${logger}: ${message} ${onexception:inner=${newline}${newline}[v${assembly-version}] ${exception:format=ToString}${newline}${exception:format=Data}${newline}}";
+ public static CompactJsonLayout ClefLogLayout = new CompactJsonLayout();
private static bool _isConfigured;
@@ -45,7 +44,7 @@ namespace NzbDrone.Common.Instrumentation
RegisterDebugger();
}
- RegisterSentry(updateApp, appFolderInfo);
+ RegisterSentry(updateApp);
if (updateApp)
{
@@ -66,7 +65,7 @@ namespace NzbDrone.Common.Instrumentation
LogManager.ReconfigExistingLoggers();
}
- private static void RegisterSentry(bool updateClient, IAppFolderInfo appFolderInfo)
+ private static void RegisterSentry(bool updateClient)
{
string dsn;
@@ -81,7 +80,7 @@ namespace NzbDrone.Common.Instrumentation
: "https://0522924d625c497f86fc2a1b22aaf21d@sentry.servarr.com/16";
}
- var target = new SentryTarget(dsn, appFolderInfo)
+ var target = new SentryTarget(dsn)
{
Name = "sentryTarget",
Layout = "${message}"
@@ -119,7 +118,11 @@ namespace NzbDrone.Common.Instrumentation
? formatEnumValue
: ConsoleLogFormat.Standard;
- ConfigureConsoleLayout(coloredConsoleTarget, logFormat);
+ coloredConsoleTarget.Layout = logFormat switch
+ {
+ ConsoleLogFormat.Clef => ClefLogLayout,
+ _ => ConsoleLogLayout
+ };
var loggingRule = new LoggingRule("*", level, coloredConsoleTarget);
@@ -136,7 +139,7 @@ namespace NzbDrone.Common.Instrumentation
private static void RegisterAppFile(IAppFolderInfo appFolderInfo, string name, string fileName, int maxArchiveFiles, LogLevel minLogLevel)
{
- var fileTarget = new CleansingFileTarget();
+ var fileTarget = new NzbDroneFileTarget();
fileTarget.Name = name;
fileTarget.FileName = Path.Combine(appFolderInfo.GetLogFolder(), fileName);
@@ -149,7 +152,7 @@ namespace NzbDrone.Common.Instrumentation
fileTarget.MaxArchiveFiles = maxArchiveFiles;
fileTarget.EnableFileDelete = true;
fileTarget.ArchiveNumbering = ArchiveNumberingMode.Rolling;
- fileTarget.Layout = FileLogLayout;
+ fileTarget.Layout = FILE_LOG_LAYOUT;
var loggingRule = new LoggingRule("*", minLogLevel, fileTarget);
@@ -168,7 +171,7 @@ namespace NzbDrone.Common.Instrumentation
fileTarget.ConcurrentWrites = false;
fileTarget.ConcurrentWriteAttemptDelay = 50;
fileTarget.ConcurrentWriteAttempts = 100;
- fileTarget.Layout = FileLogLayout;
+ fileTarget.Layout = FILE_LOG_LAYOUT;
var loggingRule = new LoggingRule("*", LogLevel.Trace, fileTarget);
@@ -213,15 +216,6 @@ namespace NzbDrone.Common.Instrumentation
{
return GetLogger(obj.GetType());
}
-
- public static void ConfigureConsoleLayout(ColoredConsoleTarget target, ConsoleLogFormat format)
- {
- target.Layout = format switch
- {
- ConsoleLogFormat.Clef => NzbDroneLogger.ClefLogLayout,
- _ => NzbDroneLogger.CleansingConsoleLayout
- };
- }
}
public enum ConsoleLogFormat
diff --git a/src/NzbDrone.Common/Instrumentation/Sentry/SentryTarget.cs b/src/NzbDrone.Common/Instrumentation/Sentry/SentryTarget.cs
index 3f8d4c227..39b0a920a 100644
--- a/src/NzbDrone.Common/Instrumentation/Sentry/SentryTarget.cs
+++ b/src/NzbDrone.Common/Instrumentation/Sentry/SentryTarget.cs
@@ -9,7 +9,6 @@ using NLog;
using NLog.Common;
using NLog.Targets;
using NzbDrone.Common.EnvironmentInfo;
-using NzbDrone.Common.Extensions;
using Sentry;
namespace NzbDrone.Common.Instrumentation.Sentry
@@ -100,7 +99,7 @@ namespace NzbDrone.Common.Instrumentation.Sentry
public bool FilterEvents { get; set; }
public bool SentryEnabled { get; set; }
- public SentryTarget(string dsn, IAppFolderInfo appFolderInfo)
+ public SentryTarget(string dsn)
{
_sdk = SentrySdk.Init(o =>
{
@@ -108,33 +107,9 @@ namespace NzbDrone.Common.Instrumentation.Sentry
o.AttachStacktrace = true;
o.MaxBreadcrumbs = 200;
o.Release = $"{BuildInfo.AppName}@{BuildInfo.Release}";
- o.SetBeforeSend(x => SentryCleanser.CleanseEvent(x));
- o.SetBeforeBreadcrumb(x => SentryCleanser.CleanseBreadcrumb(x));
+ o.BeforeSend = x => SentryCleanser.CleanseEvent(x);
+ o.BeforeBreadcrumb = x => SentryCleanser.CleanseBreadcrumb(x);
o.Environment = BuildInfo.Branch;
-
- // Crash free run statistics (sends a ping for healthy and for crashes sessions)
- o.AutoSessionTracking = false;
-
- // Caches files in the event device is offline
- // Sentry creates a 'sentry' sub directory, no need to concat here
- o.CacheDirectoryPath = appFolderInfo.GetAppDataPath();
-
- // default environment is production
- if (!RuntimeInfo.IsProduction)
- {
- if (RuntimeInfo.IsDevelopment)
- {
- o.Environment = "development";
- }
- else if (RuntimeInfo.IsTesting)
- {
- o.Environment = "testing";
- }
- else
- {
- o.Environment = "other";
- }
- }
});
InitializeScope();
@@ -152,7 +127,7 @@ namespace NzbDrone.Common.Instrumentation.Sentry
{
SentrySdk.ConfigureScope(scope =>
{
- scope.User = new SentryUser
+ scope.User = new User
{
Id = HashUtil.AnonymousToken()
};
@@ -194,7 +169,9 @@ namespace NzbDrone.Common.Instrumentation.Sentry
private void OnError(Exception ex)
{
- if (ex is WebException webException)
+ var webException = ex as WebException;
+
+ if (webException != null)
{
var response = webException.Response as HttpWebResponse;
var statusCode = response?.StatusCode;
@@ -313,21 +290,13 @@ namespace NzbDrone.Common.Instrumentation.Sentry
}
}
- var level = LoggingLevelMap[logEvent.Level];
var sentryEvent = new SentryEvent(logEvent.Exception)
{
- Level = level,
+ Level = LoggingLevelMap[logEvent.Level],
Logger = logEvent.LoggerName,
Message = logEvent.FormattedMessage
};
- if (level is SentryLevel.Fatal && logEvent.Exception is not null)
- {
- // Usages of 'fatal' here indicates the process will crash. In Sentry this is represented with
- // the 'unhandled' exception flag
- logEvent.Exception.SetSentryMechanism("Logger.Fatal", "Logger.Fatal was called", false);
- }
-
sentryEvent.SetExtras(extras);
sentryEvent.SetFingerprint(fingerPrint);
diff --git a/src/NzbDrone.Common/Lidarr.Common.csproj b/src/NzbDrone.Common/Lidarr.Common.csproj
index 2e5bacde4..10870072d 100644
--- a/src/NzbDrone.Common/Lidarr.Common.csproj
+++ b/src/NzbDrone.Common/Lidarr.Common.csproj
@@ -6,17 +6,17 @@
-
+
-
+
-
-
+
+
-
+
diff --git a/src/NzbDrone.Common/PathEqualityComparer.cs b/src/NzbDrone.Common/PathEqualityComparer.cs
index e8322864a..bd6fa430d 100644
--- a/src/NzbDrone.Common/PathEqualityComparer.cs
+++ b/src/NzbDrone.Common/PathEqualityComparer.cs
@@ -1,4 +1,3 @@
-using System;
using System.Collections.Generic;
using NzbDrone.Common.EnvironmentInfo;
using NzbDrone.Common.Extensions;
@@ -7,7 +6,7 @@ namespace NzbDrone.Common
{
public class PathEqualityComparer : IEqualityComparer
{
- public static readonly PathEqualityComparer Instance = new ();
+ public static readonly PathEqualityComparer Instance = new PathEqualityComparer();
private PathEqualityComparer()
{
@@ -20,19 +19,12 @@ namespace NzbDrone.Common
public int GetHashCode(string obj)
{
- try
+ if (OsInfo.IsWindows)
{
- if (OsInfo.IsWindows)
- {
- return obj.CleanFilePath().Normalize().ToLower().GetHashCode();
- }
+ return obj.CleanFilePath().Normalize().ToLower().GetHashCode();
+ }
- return obj.CleanFilePath().Normalize().GetHashCode();
- }
- catch (ArgumentException ex)
- {
- throw new ArgumentException($"Invalid path: {obj}", ex);
- }
+ return obj.CleanFilePath().Normalize().GetHashCode();
}
}
}
diff --git a/src/NzbDrone.Common/Processes/ProcessProvider.cs b/src/NzbDrone.Common/Processes/ProcessProvider.cs
index bee099319..4e23a7e0c 100644
--- a/src/NzbDrone.Common/Processes/ProcessProvider.cs
+++ b/src/NzbDrone.Common/Processes/ProcessProvider.cs
@@ -6,7 +6,6 @@ using System.ComponentModel;
using System.Diagnostics;
using System.IO;
using System.Linq;
-using System.Text;
using NLog;
using NzbDrone.Common.EnvironmentInfo;
using NzbDrone.Common.Model;
@@ -118,9 +117,7 @@ namespace NzbDrone.Common.Processes
UseShellExecute = false,
RedirectStandardError = true,
RedirectStandardOutput = true,
- RedirectStandardInput = true,
- StandardOutputEncoding = Encoding.UTF8,
- StandardErrorEncoding = Encoding.UTF8
+ RedirectStandardInput = true
};
if (environmentVariables != null)
@@ -316,7 +313,7 @@ namespace NzbDrone.Common.Processes
processInfo = new ProcessInfo();
processInfo.Id = process.Id;
processInfo.Name = process.ProcessName;
- processInfo.StartPath = process.MainModule?.FileName;
+ processInfo.StartPath = process.MainModule.FileName;
if (process.Id != GetCurrentProcessId() && process.HasExited)
{
diff --git a/src/NzbDrone.Common/Reflection/ReflectionExtensions.cs b/src/NzbDrone.Common/Reflection/ReflectionExtensions.cs
index a47137bfd..8f016450d 100644
--- a/src/NzbDrone.Common/Reflection/ReflectionExtensions.cs
+++ b/src/NzbDrone.Common/Reflection/ReflectionExtensions.cs
@@ -34,8 +34,7 @@ namespace NzbDrone.Common.Reflection
|| type == typeof(string)
|| type == typeof(DateTime)
|| type == typeof(Version)
- || type == typeof(decimal)
- || (type.IsGenericType && type.GetGenericTypeDefinition() == typeof(KeyValuePair<,>));
+ || type == typeof(decimal);
}
public static bool IsReadable(this PropertyInfo propertyInfo)
diff --git a/src/NzbDrone.Core.Test/Datastore/Converters/TimeSpanConverterFixture.cs b/src/NzbDrone.Core.Test/Datastore/Converters/TimeSpanConverterFixture.cs
deleted file mode 100644
index 79d0adaee..000000000
--- a/src/NzbDrone.Core.Test/Datastore/Converters/TimeSpanConverterFixture.cs
+++ /dev/null
@@ -1,43 +0,0 @@
-using System;
-using System.Data.SQLite;
-using FluentAssertions;
-using NUnit.Framework;
-using NzbDrone.Core.Datastore.Converters;
-using NzbDrone.Core.Test.Framework;
-
-namespace NzbDrone.Core.Test.Datastore.Converters;
-
-[TestFixture]
-public class TimeSpanConverterFixture : CoreTest
-{
- private SQLiteParameter _param;
-
- [SetUp]
- public void Setup()
- {
- _param = new SQLiteParameter();
- }
-
- [Test]
- public void should_return_string_when_saving_timespan_to_db()
- {
- var span = TimeSpan.FromMilliseconds(10);
-
- Subject.SetValue(_param, span);
- _param.Value.Should().Be(span.ToString());
- }
-
- [Test]
- public void should_return_timespan_when_getting_string_from_db()
- {
- var span = TimeSpan.FromMilliseconds(10);
-
- Subject.Parse(span.ToString()).Should().Be(span);
- }
-
- [Test]
- public void should_return_zero_timespan_for_db_null_value_when_getting_from_db()
- {
- Subject.Parse(null).Should().Be(TimeSpan.Zero);
- }
-}
diff --git a/src/NzbDrone.Core.Test/Datastore/DatabaseVersionParserFixture.cs b/src/NzbDrone.Core.Test/Datastore/DatabaseVersionParserFixture.cs
deleted file mode 100644
index 05bf04fea..000000000
--- a/src/NzbDrone.Core.Test/Datastore/DatabaseVersionParserFixture.cs
+++ /dev/null
@@ -1,38 +0,0 @@
-using FluentAssertions;
-using NUnit.Framework;
-using NzbDrone.Core.Datastore;
-
-namespace NzbDrone.Core.Test.Datastore;
-
-[TestFixture]
-public class DatabaseVersionParserFixture
-{
- [TestCase("3.44.2", 3, 44, 2)]
- public void should_parse_sqlite_database_version(string serverVersion, int majorVersion, int minorVersion, int buildVersion)
- {
- var version = DatabaseVersionParser.ParseServerVersion(serverVersion);
-
- version.Should().NotBeNull();
- version.Major.Should().Be(majorVersion);
- version.Minor.Should().Be(minorVersion);
- version.Build.Should().Be(buildVersion);
- }
-
- [TestCase("14.8 (Debian 14.8-1.pgdg110+1)", 14, 8, null)]
- [TestCase("16.3 (Debian 16.3-1.pgdg110+1)", 16, 3, null)]
- [TestCase("16.3 - Percona Distribution", 16, 3, null)]
- [TestCase("17.0 - Percona Server", 17, 0, null)]
- public void should_parse_postgres_database_version(string serverVersion, int majorVersion, int minorVersion, int? buildVersion)
- {
- var version = DatabaseVersionParser.ParseServerVersion(serverVersion);
-
- version.Should().NotBeNull();
- version.Major.Should().Be(majorVersion);
- version.Minor.Should().Be(minorVersion);
-
- if (buildVersion.HasValue)
- {
- version.Build.Should().Be(buildVersion.Value);
- }
- }
-}
diff --git a/src/NzbDrone.Core.Test/DiskSpace/DiskSpaceServiceFixture.cs b/src/NzbDrone.Core.Test/DiskSpace/DiskSpaceServiceFixture.cs
index dd501374c..948ab3a54 100644
--- a/src/NzbDrone.Core.Test/DiskSpace/DiskSpaceServiceFixture.cs
+++ b/src/NzbDrone.Core.Test/DiskSpace/DiskSpaceServiceFixture.cs
@@ -103,7 +103,6 @@ namespace NzbDrone.Core.Test.DiskSpace
[TestCase("/var/lib/docker")]
[TestCase("/some/place/docker/aufs")]
[TestCase("/etc/network")]
- [TestCase("/Volumes/.timemachine/ABC123456-A1BC-12A3B45678C9/2025-05-13-181401.backup")]
public void should_not_check_diskspace_for_irrelevant_mounts(string path)
{
var mount = new Mock();
diff --git a/src/NzbDrone.Core.Test/Download/CompletedDownloadServiceTests/ImportFixture.cs b/src/NzbDrone.Core.Test/Download/CompletedDownloadServiceTests/ImportFixture.cs
index 9719b7f1f..16f6cfd1a 100644
--- a/src/NzbDrone.Core.Test/Download/CompletedDownloadServiceTests/ImportFixture.cs
+++ b/src/NzbDrone.Core.Test/Download/CompletedDownloadServiceTests/ImportFixture.cs
@@ -183,8 +183,6 @@ namespace NzbDrone.Core.Test.Download.CompletedDownloadServiceTests
{
GivenArtistMatch();
- var tracks = Builder