Compare commits

..

21 Commits

Author SHA1 Message Date
Bogdan
b83a760873 Bump frontend packages 2024-10-20 13:22:14 +03:00
Bogdan
22ab50f76d Bump dotnet to 6.0.35 2024-10-20 13:22:14 +03:00
Mark McDowall
66758ca006 New: Show update settings on all platforms
(cherry picked from commit c023fc700896c7f0751c4ac63c4e1a89d6e1a9bb)
2024-10-20 11:43:51 +03:00
Mark McDowall
e7d7bc79f4 New: Allow major version updates to be installed
(cherry picked from commit 0e95ba2021b23cc65bce0a0620dd48e355250dab)
2024-10-20 11:43:51 +03:00
Bogdan
cfccb4f9c3 Bump version to 0.4.2 2024-10-20 08:07:10 +03:00
Mark McDowall
9312f17041 New: Use 307 redirect for requests missing URL Base
(cherry picked from commit 39074b0b1d040969f86d787c2346d5ed5a9f72dc)
2024-10-08 02:20:37 +03:00
Bogdan
8192c22910 Bump macOS runner version to 13 2024-10-06 16:30:37 +03:00
ManiMatter
0b1d6b677a Add '.temp*' to .gitignore (#3778) 2024-10-02 22:53:34 +03:00
Bogdan
d666df0189 Bump version to 0.4.1 2024-09-29 08:19:59 +03:00
Bogdan
10d8f345c1 Display naming example errors when all fields are empty
(cherry picked from commit 768af433d1655c587a9eee9b100f306ba4345f88)
2024-09-28 05:18:41 +03:00
Robin Dadswell
fb720b8714 Fixed: Telegram log message including token
(cherry picked from commit a7cb264cc8013d9a56aee7d5e41acfd76cde5f96)
2024-09-28 05:18:29 +03:00
Servarr
e8131b5791 Automated API Docs update 2024-09-25 10:34:30 +03:00
Bogdan
4f793f6b93 Remove $ from Discord delete notifications 2024-09-25 10:28:00 +03:00
Bogdan
4215c21c94 Add package needed for RemoveDiacritics 2024-09-23 05:46:26 +03:00
Paul DiLoreto
6913789adc New: Use instance name in forms authentication cookie name (#3761)
(cherry picked from commit 97ebaf279650082c6baee9563ef179921c5ed25a)
(cherry picked from commit faf9173b3b4a298e3afa9a186e66ba6764ac055e)
(cherry picked from commit 75fae9262c6ca003d24df9fcf035d75b1e90f994)

---------

Co-authored-by: Mark McDowall <mark@mcdowall.ca>
2024-09-23 05:45:01 +03:00
Mark McDowall
09e0c40792 Fixed: Limit redirects after login to local paths
(cherry picked from commit 14005d8d1054eafaba808337a109d5812f3e79e6)
2024-09-23 05:41:21 +03:00
Mark McDowall
baff805551 New: Return downloading magnets from Transmission
(cherry picked from commit 11a9dcb3890eaf99602900f37e64007f2fbf9b8e)
2024-09-23 05:40:25 +03:00
Bogdan
c885fe43cd Fix disabled style for monitor toggle button
(cherry picked from commit dde28cbd7e16b85f78d38c8dde7cf6bbb6119bb3)
2024-09-23 05:39:36 +03:00
Treycos
464a777722 Updated code action fixall value for VSCode
(cherry picked from commit 8af4246ff9baee4c291550102769a1186f65dc29)
2024-09-23 05:39:19 +03:00
momo
89e5999c85 Fix description for API key as query parameter
(cherry picked from commit 30c36fdc3baa686102ff124833c7963fc786f251)
2024-09-23 05:36:05 +03:00
Bogdan
b6fa332550 Ignore metadata tests temporarily once again 2024-09-23 05:35:27 +03:00
85 changed files with 2449 additions and 2469 deletions

1
.gitignore vendored
View File

@@ -120,6 +120,7 @@ _artifacts
_rawPackage/
_dotTrace*
_tests/
_temp*
*.Result.xml
coverage*.xml
coverage*.json

View File

@@ -9,18 +9,18 @@ variables:
testsFolder: './_tests'
yarnCacheFolder: $(Pipeline.Workspace)/.yarn
nugetCacheFolder: $(Pipeline.Workspace)/.nuget/packages
majorVersion: '0.4.0'
majorVersion: '0.4.2'
minorVersion: $[counter('minorVersion', 1)]
readarrVersion: '$(majorVersion).$(minorVersion)'
buildName: '$(Build.SourceBranchName).$(readarrVersion)'
sentryOrg: 'servarr'
sentryUrl: 'https://sentry.servarr.com'
dotnetVersion: '6.0.424'
dotnetVersion: '6.0.427'
nodeVersion: '20.X'
innoVersion: '6.2.0'
windowsImage: 'windows-2022'
linuxImage: 'ubuntu-20.04'
macImage: 'macOS-12'
macImage: 'macOS-13'
trigger:
branches:

View File

@@ -9,7 +9,7 @@
"editor.formatOnSave": false,
"editor.codeActionsOnSave": {
"source.fixAll": true
"source.fixAll": "explicit"
},
"typescript.preferences.quoteStyle": "single",

View File

@@ -32,7 +32,7 @@ import LogsTableConnector from 'System/Events/LogsTableConnector';
import Logs from 'System/Logs/Logs';
import Status from 'System/Status/Status';
import Tasks from 'System/Tasks/Tasks';
import UpdatesConnector from 'System/Updates/UpdatesConnector';
import Updates from 'System/Updates/Updates';
import UnmappedFilesTableConnector from 'UnmappedFiles/UnmappedFilesTableConnector';
import getPathWithUrlBase from 'Utilities/getPathWithUrlBase';
import CutoffUnmetConnector from 'Wanted/CutoffUnmet/CutoffUnmetConnector';
@@ -247,7 +247,7 @@ function AppRoutes(props) {
<Route
path="/system/updates"
component={UpdatesConnector}
component={Updates}
/>
<Route

View File

@@ -1,6 +1,7 @@
import AuthorsAppState from './AuthorsAppState';
import CommandAppState from './CommandAppState';
import SettingsAppState from './SettingsAppState';
import SystemAppState from './SystemAppState';
import TagsAppState from './TagsAppState';
interface FilterBuilderPropOption {
@@ -35,10 +36,24 @@ export interface CustomFilter {
filers: PropertyFilter[];
}
export interface AppSectionState {
isConnected: boolean;
isReconnecting: boolean;
version: string;
prevVersion?: string;
dimensions: {
isSmallScreen: boolean;
width: number;
height: number;
};
}
interface AppState {
app: AppSectionState;
authors: AuthorsAppState;
commands: CommandAppState;
settings: SettingsAppState;
system: SystemAppState;
tags: TagsAppState;
}

View File

@@ -1,5 +1,6 @@
import AppSectionState, {
AppSectionDeleteState,
AppSectionItemState,
AppSectionSaveState,
} from 'App/State/AppSectionState';
import DownloadClient from 'typings/DownloadClient';
@@ -7,13 +8,16 @@ import ImportList from 'typings/ImportList';
import Indexer from 'typings/Indexer';
import IndexerFlag from 'typings/IndexerFlag';
import Notification from 'typings/Notification';
import { UiSettings } from 'typings/UiSettings';
import General from 'typings/Settings/General';
import UiSettings from 'typings/Settings/UiSettings';
export interface DownloadClientAppState
extends AppSectionState<DownloadClient>,
AppSectionDeleteState,
AppSectionSaveState {}
export type GeneralAppState = AppSectionItemState<General>;
export interface ImportListAppState
extends AppSectionState<ImportList>,
AppSectionDeleteState,
@@ -33,11 +37,12 @@ export type UiSettingsAppState = AppSectionState<UiSettings>;
interface SettingsAppState {
downloadClients: DownloadClientAppState;
general: GeneralAppState;
importLists: ImportListAppState;
indexerFlags: IndexerFlagSettingsAppState;
indexers: IndexerAppState;
notifications: NotificationAppState;
uiSettings: UiSettingsAppState;
ui: UiSettingsAppState;
}
export default SettingsAppState;

View File

@@ -0,0 +1,13 @@
import SystemStatus from 'typings/SystemStatus';
import Update from 'typings/Update';
import AppSectionState, { AppSectionItemState } from './AppSectionState';
export type SystemStatusAppState = AppSectionItemState<SystemStatus>;
export type UpdateAppState = AppSectionState<Update>;
interface SystemAppState {
updates: UpdateAppState;
status: SystemStatusAppState;
}
export default SystemAppState;

View File

@@ -126,15 +126,6 @@ function AuthorIndexSortMenu(props) {
>
Size on Disk
</SortMenuItem>
<SortMenuItem
name="ratings"
sortKey={sortKey}
sortDirection={sortDirection}
onPress={onSortSelect}
>
{translate('Rating')}
</SortMenuItem>
</MenuContent>
</SortMenu>
);

View File

@@ -3,9 +3,9 @@
padding: 0;
font-size: inherit;
}
.isDisabled {
color: var(--disabledColor);
cursor: not-allowed;
&.isDisabled {
color: var(--disabledColor);
cursor: not-allowed;
}
}

View File

@@ -18,7 +18,6 @@ function UpdateSettings(props) {
const {
advancedSettings,
settings,
isWindows,
packageUpdateMechanism,
onInputChange
} = props;
@@ -44,10 +43,10 @@ function UpdateSettings(props) {
value: titleCase(packageUpdateMechanism)
});
} else {
updateOptions.push({ key: 'builtIn', value: 'Built-In' });
updateOptions.push({ key: 'builtIn', value: translate('BuiltIn') });
}
updateOptions.push({ key: 'script', value: 'Script' });
updateOptions.push({ key: 'script', value: translate('Script') });
return (
<FieldSet legend={translate('Updates')}>
@@ -60,8 +59,8 @@ function UpdateSettings(props) {
<FormInputGroup
type={inputTypes.AUTO_COMPLETE}
name="branch"
helpText={usingExternalUpdateMechanism ? translate('UsingExternalUpdateMechanismBranchUsedByExternalUpdateMechanism') : translate('UsingExternalUpdateMechanismBranchToUseToUpdateReadarr')}
helpLink="https://wiki.servarr.com/readarr/faq#how-do-I-update-my-readarr"
helpText={usingExternalUpdateMechanism ? translate('BranchUpdateMechanism') : translate('BranchUpdate')}
helpLink="https://wiki.servarr.com/readarr/settings#updates"
{...branch}
values={branchValues}
onChange={onInputChange}
@@ -69,62 +68,59 @@ function UpdateSettings(props) {
/>
</FormGroup>
{
!isWindows &&
<div>
<FormGroup
advancedSettings={advancedSettings}
isAdvanced={true}
size={sizes.MEDIUM}
>
<FormLabel>{translate('Automatic')}</FormLabel>
<div>
<FormGroup
advancedSettings={advancedSettings}
isAdvanced={true}
size={sizes.MEDIUM}
>
<FormLabel>{translate('Automatic')}</FormLabel>
<FormInputGroup
type={inputTypes.CHECK}
name="updateAutomatically"
helpText={translate('UpdateAutomaticallyHelpText')}
helpTextWarning={updateMechanism.value === 'docker' ? translate('AutomaticUpdatesDisabledDocker', { appName: 'Readarr' }) : undefined}
onChange={onInputChange}
{...updateAutomatically}
/>
</FormGroup>
<FormInputGroup
type={inputTypes.CHECK}
name="updateAutomatically"
helpText={translate('UpdateAutomaticallyHelpText')}
helpTextWarning={updateMechanism.value === 'docker' ? translate('AutomaticUpdatesDisabledDocker') : undefined}
onChange={onInputChange}
{...updateAutomatically}
/>
</FormGroup>
<FormGroup
advancedSettings={advancedSettings}
isAdvanced={true}
>
<FormLabel>{translate('Mechanism')}</FormLabel>
<FormInputGroup
type={inputTypes.SELECT}
name="updateMechanism"
values={updateOptions}
helpText={translate('UpdateMechanismHelpText')}
helpLink="https://wiki.servarr.com/readarr/settings#updates"
onChange={onInputChange}
{...updateMechanism}
/>
</FormGroup>
{
updateMechanism.value === 'script' &&
<FormGroup
advancedSettings={advancedSettings}
isAdvanced={true}
>
<FormLabel>{translate('Mechanism')}</FormLabel>
<FormLabel>{translate('ScriptPath')}</FormLabel>
<FormInputGroup
type={inputTypes.SELECT}
name="updateMechanism"
values={updateOptions}
helpText={translate('UpdateMechanismHelpText')}
helpLink="https://wiki.servarr.com/readarr/faq#how-do-i-update-my-readarr"
type={inputTypes.TEXT}
name="updateScriptPath"
helpText={translate('UpdateScriptPathHelpText')}
onChange={onInputChange}
{...updateMechanism}
{...updateScriptPath}
/>
</FormGroup>
{
updateMechanism.value === 'script' &&
<FormGroup
advancedSettings={advancedSettings}
isAdvanced={true}
>
<FormLabel>{translate('ScriptPath')}</FormLabel>
<FormInputGroup
type={inputTypes.TEXT}
name="updateScriptPath"
helpText={translate('UpdateScriptPathHelpText')}
onChange={onInputChange}
{...updateScriptPath}
/>
</FormGroup>
}
</div>
}
}
</div>
</FieldSet>
);
}

View File

@@ -1,4 +1,3 @@
import _ from 'lodash';
import PropTypes from 'prop-types';
import React, { Component } from 'react';
import { connect } from 'react-redux';
@@ -15,11 +14,11 @@ function createMapStateToProps() {
(state) => state.settings.advancedSettings,
(state) => state.settings.namingExamples,
createSettingsSectionSelector(SECTION),
(advancedSettings, examples, sectionSettings) => {
(advancedSettings, namingExamples, sectionSettings) => {
return {
advancedSettings,
examples: examples.item,
examplesPopulated: !_.isEmpty(examples.item),
examples: namingExamples.item,
examplesPopulated: namingExamples.isPopulated,
...sectionSettings
};
}

View File

@@ -1,50 +0,0 @@
import PropTypes from 'prop-types';
import React, { Component } from 'react';
import InlineMarkdown from 'Components/Markdown/InlineMarkdown';
import styles from './UpdateChanges.css';
class UpdateChanges extends Component {
//
// Render
render() {
const {
title,
changes
} = this.props;
if (changes.length === 0) {
return null;
}
return (
<div>
<div className={styles.title}>{title}</div>
<ul>
{
changes.map((change, index) => {
const checkChange = change.replace(/#\d{4,5}\b/g, (match, contents) => {
return `[${match}](https://github.com/Readarr/Readarr/issues/${match.substring(1)})`;
});
return (
<li key={index}>
<InlineMarkdown data={checkChange} />
</li>
);
})
}
</ul>
</div>
);
}
}
UpdateChanges.propTypes = {
title: PropTypes.string.isRequired,
changes: PropTypes.arrayOf(PropTypes.string)
};
export default UpdateChanges;

View File

@@ -0,0 +1,43 @@
import React from 'react';
import InlineMarkdown from 'Components/Markdown/InlineMarkdown';
import styles from './UpdateChanges.css';
interface UpdateChangesProps {
title: string;
changes: string[];
}
function UpdateChanges(props: UpdateChangesProps) {
const { title, changes } = props;
if (changes.length === 0) {
return null;
}
const uniqueChanges = [...new Set(changes)];
return (
<div>
<div className={styles.title}>{title}</div>
<ul>
{uniqueChanges.map((change, index) => {
const checkChange = change.replace(
/#\d{4,5}\b/g,
(match) =>
`[${match}](https://github.com/Readarr/Readarr/issues/${match.substring(
1
)})`
);
return (
<li key={index}>
<InlineMarkdown data={checkChange} />
</li>
);
})}
</ul>
</div>
);
}
export default UpdateChanges;

View File

@@ -1,252 +0,0 @@
import _ from 'lodash';
import PropTypes from 'prop-types';
import React, { Component, Fragment } from 'react';
import Alert from 'Components/Alert';
import Icon from 'Components/Icon';
import Label from 'Components/Label';
import SpinnerButton from 'Components/Link/SpinnerButton';
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 { icons, kinds } from 'Helpers/Props';
import formatDate from 'Utilities/Date/formatDate';
import formatDateTime from 'Utilities/Date/formatDateTime';
import translate from 'Utilities/String/translate';
import UpdateChanges from './UpdateChanges';
import styles from './Updates.css';
class Updates extends Component {
//
// Render
render() {
const {
currentVersion,
isFetching,
isPopulated,
updatesError,
generalSettingsError,
items,
isInstallingUpdate,
updateMechanism,
isDocker,
updateMechanismMessage,
shortDateFormat,
longDateFormat,
timeFormat,
onInstallLatestPress
} = this.props;
const hasError = !!(updatesError || generalSettingsError);
const hasUpdates = isPopulated && !hasError && items.length > 0;
const noUpdates = isPopulated && !hasError && !items.length;
const hasUpdateToInstall = hasUpdates && _.some(items, { installable: true, latest: true });
const noUpdateToInstall = hasUpdates && !hasUpdateToInstall;
const externalUpdaterPrefix = 'Unable to update Readarr directly,';
const externalUpdaterMessages = {
external: 'Readarr is configured to use an external update mechanism',
apt: 'use apt to install the update',
docker: 'update the docker container to receive the update'
};
return (
<PageContent title={translate('Updates')}>
<PageContentBody>
{
!isPopulated && !hasError &&
<LoadingIndicator />
}
{
noUpdates &&
<Alert kind={kinds.INFO}>
{translate('NoUpdatesAreAvailable')}
</Alert>
}
{
hasUpdateToInstall &&
<div className={styles.messageContainer}>
{
(updateMechanism === 'builtIn' || updateMechanism === 'script') && !isDocker ?
<SpinnerButton
className={styles.updateAvailable}
kind={kinds.PRIMARY}
isSpinning={isInstallingUpdate}
onPress={onInstallLatestPress}
>
Install Latest
</SpinnerButton> :
<Fragment>
<Icon
name={icons.WARNING}
kind={kinds.WARNING}
size={30}
/>
<div className={styles.message}>
{externalUpdaterPrefix} <InlineMarkdown data={updateMechanismMessage || externalUpdaterMessages[updateMechanism] || externalUpdaterMessages.external} />
</div>
</Fragment>
}
{
isFetching &&
<LoadingIndicator
className={styles.loading}
size={20}
/>
}
</div>
}
{
noUpdateToInstall &&
<div className={styles.messageContainer}>
<Icon
className={styles.upToDateIcon}
name={icons.CHECK_CIRCLE}
size={30}
/>
<div className={styles.message}>
The latest version of Readarr is already installed
</div>
{
isFetching &&
<LoadingIndicator
className={styles.loading}
size={20}
/>
}
</div>
}
{
hasUpdates &&
<div>
{
items.map((update) => {
const hasChanges = !!update.changes;
return (
<div
key={update.version}
className={styles.update}
>
<div className={styles.info}>
<div className={styles.version}>{update.version}</div>
<div className={styles.space}>&mdash;</div>
<div
className={styles.date}
title={formatDateTime(update.releaseDate, longDateFormat, timeFormat)}
>
{formatDate(update.releaseDate, shortDateFormat)}
</div>
{
update.branch === 'master' ?
null :
<Label
className={styles.label}
>
{update.branch}
</Label>
}
{
update.version === currentVersion ?
<Label
className={styles.label}
kind={kinds.SUCCESS}
title={formatDateTime(update.installedOn, longDateFormat, timeFormat)}
>
Currently Installed
</Label> :
null
}
{
update.version !== currentVersion && update.installedOn ?
<Label
className={styles.label}
kind={kinds.INVERSE}
title={formatDateTime(update.installedOn, longDateFormat, timeFormat)}
>
Previously Installed
</Label> :
null
}
</div>
{
!hasChanges &&
<div>
{translate('MaintenanceRelease')}
</div>
}
{
hasChanges &&
<div className={styles.changes}>
<UpdateChanges
title={translate('New')}
changes={update.changes.new}
/>
<UpdateChanges
title={translate('Fixed')}
changes={update.changes.fixed}
/>
</div>
}
</div>
);
})
}
</div>
}
{
!!updatesError &&
<div>
Failed to fetch updates
</div>
}
{
!!generalSettingsError &&
<div>
Failed to update settings
</div>
}
</PageContentBody>
</PageContent>
);
}
}
Updates.propTypes = {
currentVersion: PropTypes.string.isRequired,
isFetching: PropTypes.bool.isRequired,
isPopulated: PropTypes.bool.isRequired,
updatesError: PropTypes.object,
generalSettingsError: PropTypes.object,
items: PropTypes.array.isRequired,
isInstallingUpdate: PropTypes.bool.isRequired,
isDocker: PropTypes.bool.isRequired,
updateMechanism: PropTypes.string,
updateMechanismMessage: PropTypes.string,
shortDateFormat: PropTypes.string.isRequired,
longDateFormat: PropTypes.string.isRequired,
timeFormat: PropTypes.string.isRequired,
onInstallLatestPress: PropTypes.func.isRequired
};
export default Updates;

View File

@@ -0,0 +1,303 @@
import React, { useCallback, useEffect, useMemo, useState } from 'react';
import { useDispatch, useSelector } from 'react-redux';
import { createSelector } from 'reselect';
import AppState from 'App/State/AppState';
import * as commandNames from 'Commands/commandNames';
import Alert from 'Components/Alert';
import Icon from 'Components/Icon';
import Label from 'Components/Label';
import SpinnerButton from 'Components/Link/SpinnerButton';
import LoadingIndicator from 'Components/Loading/LoadingIndicator';
import InlineMarkdown from 'Components/Markdown/InlineMarkdown';
import ConfirmModal from 'Components/Modal/ConfirmModal';
import PageContent from 'Components/Page/PageContent';
import PageContentBody from 'Components/Page/PageContentBody';
import { icons, kinds } from 'Helpers/Props';
import { executeCommand } from 'Store/Actions/commandActions';
import { fetchGeneralSettings } from 'Store/Actions/settingsActions';
import { fetchUpdates } from 'Store/Actions/systemActions';
import createCommandExecutingSelector from 'Store/Selectors/createCommandExecutingSelector';
import createSystemStatusSelector from 'Store/Selectors/createSystemStatusSelector';
import createUISettingsSelector from 'Store/Selectors/createUISettingsSelector';
import { UpdateMechanism } from 'typings/Settings/General';
import formatDate from 'Utilities/Date/formatDate';
import formatDateTime from 'Utilities/Date/formatDateTime';
import translate from 'Utilities/String/translate';
import UpdateChanges from './UpdateChanges';
import styles from './Updates.css';
const VERSION_REGEX = /\d+\.\d+\.\d+\.\d+/i;
function createUpdatesSelector() {
return createSelector(
(state: AppState) => state.system.updates,
(state: AppState) => state.settings.general,
(updates, generalSettings) => {
const { error: updatesError, items } = updates;
const isFetching = updates.isFetching || generalSettings.isFetching;
const isPopulated = updates.isPopulated && generalSettings.isPopulated;
return {
isFetching,
isPopulated,
updatesError,
generalSettingsError: generalSettings.error,
items,
updateMechanism: generalSettings.item.updateMechanism,
};
}
);
}
function Updates() {
const currentVersion = useSelector((state: AppState) => state.app.version);
const { packageUpdateMechanismMessage } = useSelector(
createSystemStatusSelector()
);
const { shortDateFormat, longDateFormat, timeFormat } = useSelector(
createUISettingsSelector()
);
const isInstallingUpdate = useSelector(
createCommandExecutingSelector(commandNames.APPLICATION_UPDATE)
);
const {
isFetching,
isPopulated,
updatesError,
generalSettingsError,
items,
updateMechanism,
} = useSelector(createUpdatesSelector());
const dispatch = useDispatch();
const [isMajorUpdateModalOpen, setIsMajorUpdateModalOpen] = useState(false);
const hasError = !!(updatesError || generalSettingsError);
const hasUpdates = isPopulated && !hasError && items.length > 0;
const noUpdates = isPopulated && !hasError && !items.length;
const externalUpdaterPrefix = translate('UpdateAppDirectlyLoadError');
const externalUpdaterMessages: Partial<Record<UpdateMechanism, string>> = {
external: translate('ExternalUpdater'),
apt: translate('AptUpdater'),
docker: translate('DockerUpdater'),
};
const { isMajorUpdate, hasUpdateToInstall } = useMemo(() => {
const majorVersion = parseInt(
currentVersion.match(VERSION_REGEX)?.[0] ?? '0'
);
const latestVersion = items[0]?.version;
const latestMajorVersion = parseInt(
latestVersion?.match(VERSION_REGEX)?.[0] ?? '0'
);
return {
isMajorUpdate: latestMajorVersion > majorVersion,
hasUpdateToInstall: items.some(
(update) => update.installable && update.latest
),
};
}, [currentVersion, items]);
const noUpdateToInstall = hasUpdates && !hasUpdateToInstall;
const handleInstallLatestPress = useCallback(() => {
if (isMajorUpdate) {
setIsMajorUpdateModalOpen(true);
} else {
dispatch(executeCommand({ name: commandNames.APPLICATION_UPDATE }));
}
}, [isMajorUpdate, setIsMajorUpdateModalOpen, dispatch]);
const handleInstallLatestMajorVersionPress = useCallback(() => {
setIsMajorUpdateModalOpen(false);
dispatch(
executeCommand({
name: commandNames.APPLICATION_UPDATE,
installMajorUpdate: true,
})
);
}, [setIsMajorUpdateModalOpen, dispatch]);
const handleCancelMajorVersionPress = useCallback(() => {
setIsMajorUpdateModalOpen(false);
}, [setIsMajorUpdateModalOpen]);
useEffect(() => {
dispatch(fetchUpdates());
dispatch(fetchGeneralSettings());
}, [dispatch]);
return (
<PageContent title={translate('Updates')}>
<PageContentBody>
{isPopulated || hasError ? null : <LoadingIndicator />}
{noUpdates ? (
<Alert kind={kinds.INFO}>{translate('NoUpdatesAreAvailable')}</Alert>
) : null}
{hasUpdateToInstall ? (
<div className={styles.messageContainer}>
{updateMechanism === 'builtIn' || updateMechanism === 'script' ? (
<SpinnerButton
kind={kinds.PRIMARY}
isSpinning={isInstallingUpdate}
onPress={handleInstallLatestPress}
>
{translate('InstallLatest')}
</SpinnerButton>
) : (
<>
<Icon name={icons.WARNING} kind={kinds.WARNING} size={30} />
<div className={styles.message}>
{externalUpdaterPrefix}{' '}
<InlineMarkdown
data={
packageUpdateMechanismMessage ||
externalUpdaterMessages[updateMechanism] ||
externalUpdaterMessages.external
}
/>
</div>
</>
)}
{isFetching ? (
<LoadingIndicator className={styles.loading} size={20} />
) : null}
</div>
) : null}
{noUpdateToInstall && (
<div className={styles.messageContainer}>
<Icon
className={styles.upToDateIcon}
name={icons.CHECK_CIRCLE}
size={30}
/>
<div className={styles.message}>{translate('OnLatestVersion')}</div>
{isFetching && (
<LoadingIndicator className={styles.loading} size={20} />
)}
</div>
)}
{hasUpdates && (
<div>
{items.map((update) => {
return (
<div key={update.version} className={styles.update}>
<div className={styles.info}>
<div className={styles.version}>{update.version}</div>
<div className={styles.space}>&mdash;</div>
<div
className={styles.date}
title={formatDateTime(
update.releaseDate,
longDateFormat,
timeFormat
)}
>
{formatDate(update.releaseDate, shortDateFormat)}
</div>
{update.branch === 'master' ? null : (
<Label className={styles.label}>{update.branch}</Label>
)}
{update.version === currentVersion ? (
<Label
className={styles.label}
kind={kinds.SUCCESS}
title={formatDateTime(
update.installedOn,
longDateFormat,
timeFormat
)}
>
{translate('CurrentlyInstalled')}
</Label>
) : null}
{update.version !== currentVersion && update.installedOn ? (
<Label
className={styles.label}
kind={kinds.INVERSE}
title={formatDateTime(
update.installedOn,
longDateFormat,
timeFormat
)}
>
{translate('PreviouslyInstalled')}
</Label>
) : null}
</div>
{update.changes ? (
<div>
<UpdateChanges
title={translate('New')}
changes={update.changes.new}
/>
<UpdateChanges
title={translate('Fixed')}
changes={update.changes.fixed}
/>
</div>
) : (
<div>{translate('MaintenanceRelease')}</div>
)}
</div>
);
})}
</div>
)}
{updatesError ? (
<Alert kind={kinds.WARNING}>
{translate('FailedToFetchUpdates')}
</Alert>
) : null}
{generalSettingsError ? (
<Alert kind={kinds.DANGER}>
{translate('FailedToFetchSettings')}
</Alert>
) : null}
<ConfirmModal
isOpen={isMajorUpdateModalOpen}
kind={kinds.WARNING}
title={translate('InstallMajorVersionUpdate')}
message={
<div>
<div>{translate('InstallMajorVersionUpdateMessage')}</div>
<div>
<InlineMarkdown
data={translate('InstallMajorVersionUpdateMessageLink', {
domain: 'readarr.com',
url: 'https://readarr.com/#downloads',
})}
/>
</div>
</div>
}
confirmLabel={translate('Install')}
onConfirm={handleInstallLatestMajorVersionPress}
onCancel={handleCancelMajorVersionPress}
/>
</PageContentBody>
</PageContent>
);
}
export default Updates;

View File

@@ -0,0 +1,45 @@
export type UpdateMechanism =
| 'builtIn'
| 'script'
| 'external'
| 'apt'
| 'docker';
export default interface General {
bindAddress: string;
port: number;
sslPort: number;
enableSsl: boolean;
launchBrowser: boolean;
authenticationMethod: string;
authenticationRequired: string;
analyticsEnabled: boolean;
username: string;
password: string;
passwordConfirmation: string;
logLevel: string;
consoleLogLevel: string;
branch: string;
apiKey: string;
sslCertPath: string;
sslCertPassword: string;
urlBase: string;
instanceName: string;
applicationUrl: string;
updateAutomatically: boolean;
updateMechanism: UpdateMechanism;
updateScriptPath: string;
proxyEnabled: boolean;
proxyType: string;
proxyHostname: string;
proxyPort: number;
proxyUsername: string;
proxyPassword: string;
proxyBypassFilter: string;
proxyBypassLocalAddresses: boolean;
certificateValidation: string;
backupFolder: string;
backupInterval: number;
backupRetention: number;
id: number;
}

View File

@@ -1,4 +1,5 @@
export interface UiSettings {
export default interface UiSettings {
theme: 'auto' | 'dark' | 'light';
showRelativeDates: boolean;
shortDateFormat: string;
longDateFormat: string;

View File

@@ -0,0 +1,32 @@
interface SystemStatus {
appData: string;
appName: string;
authentication: string;
branch: string;
buildTime: string;
instanceName: string;
isAdmin: boolean;
isDebug: boolean;
isDocker: boolean;
isLinux: boolean;
isNetCore: boolean;
isOsx: boolean;
isProduction: boolean;
isUserInteractive: boolean;
isWindows: boolean;
migrationVersion: number;
mode: string;
osName: string;
osVersion: string;
packageUpdateMechanism: string;
packageUpdateMechanismMessage: string;
runtimeName: string;
runtimeVersion: string;
sqliteVersion: string;
startTime: string;
startupPath: string;
urlBase: string;
version: string;
}
export default SystemStatus;

View File

@@ -0,0 +1,20 @@
export interface Changes {
new: string[];
fixed: string[];
}
interface Update {
version: string;
branch: string;
releaseDate: string;
fileName: string;
url: string;
installed: boolean;
installedOn: string;
installable: boolean;
latest: boolean;
changes: Changes | null;
hash: string;
}
export default Update;

View File

@@ -25,34 +25,33 @@
"defaults"
],
"dependencies": {
"@fortawesome/fontawesome-free": "6.4.0",
"@fortawesome/fontawesome-svg-core": "6.4.0",
"@fortawesome/free-regular-svg-icons": "6.4.0",
"@fortawesome/free-solid-svg-icons": "6.4.0",
"@fortawesome/react-fontawesome": "0.2.0",
"@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",
"@microsoft/signalr": "6.0.25",
"@sentry/browser": "7.51.2",
"@sentry/integrations": "7.51.2",
"@types/node": "18.19.31",
"@sentry/browser": "7.119.1",
"@sentry/integrations": "7.119.1",
"@types/node": "20.16.11",
"@types/react": "18.2.79",
"@types/react-dom": "18.2.25",
"ansi-colors": "4.1.3",
"classnames": "2.3.2",
"classnames": "2.5.1",
"clipboard": "2.0.11",
"connected-react-router": "6.9.3",
"element-class": "0.2.2",
"filesize": "10.0.7",
"filesize": "10.1.6",
"fuse.js": "6.6.2",
"history": "4.10.1",
"jdu": "1.0.0",
"jquery": "3.7.0",
"jquery": "3.7.1",
"lodash": "4.17.21",
"mobile-detect": "1.4.5",
"moment": "2.29.4",
"moment": "2.30.1",
"mousetrap": "1.6.5",
"normalize.css": "8.0.1",
"prop-types": "15.8.1",
"qs": "6.11.1",
"qs": "6.13.0",
"react": "17.0.2",
"react-addons-shallow-compare": "15.6.3",
"react-async-script": "1.2.0",
@@ -64,7 +63,7 @@
"react-dnd-touch-backend": "14.1.1",
"react-document-title": "2.0.3",
"react-dom": "17.0.2",
"react-focus-lock": "2.5.2",
"react-focus-lock": "2.9.4",
"react-google-recaptcha": "2.1.0",
"react-lazyload": "3.2.0",
"react-measure": "2.5.2",
@@ -73,74 +72,71 @@
"react-redux": "7.2.4",
"react-router": "5.2.0",
"react-router-dom": "5.2.0",
"react-slider": "1.3.1",
"react-tabs": "3.2.2",
"react-text-truncate": "0.18.0",
"react-slider": "1.3.3",
"react-tabs": "4.3.0",
"react-text-truncate": "0.19.0",
"react-virtualized": "9.21.1",
"redux": "4.1.0",
"redux": "4.2.1",
"redux-actions": "2.6.5",
"redux-batched-actions": "0.5.0",
"redux-localstorage": "0.4.1",
"redux-thunk": "2.3.0",
"redux-thunk": "2.4.2",
"reselect": "4.1.8",
"stacktrace-js": "2.0.2",
"typescript": "5.1.6"
},
"devDependencies": {
"@babel/core": "7.24.4",
"@babel/eslint-parser": "7.24.1",
"@babel/plugin-proposal-export-default-from": "7.24.1",
"@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.24.4",
"@babel/preset-react": "7.24.1",
"@babel/preset-typescript": "7.24.1",
"@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.0",
"@types/redux-actions": "2.6.2",
"@types/react-lazyload": "3.2.3",
"@types/redux-actions": "2.6.5",
"@typescript-eslint/eslint-plugin": "6.21.0",
"@typescript-eslint/parser": "6.21.0",
"autoprefixer": "10.4.14",
"babel-loader": "9.1.3",
"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.37.0",
"core-js": "3.38.1",
"css-loader": "6.8.1",
"css-modules-typescript-loader": "4.0.1",
"eslint": "8.57.0",
"eslint": "8.57.1",
"eslint-config-prettier": "8.10.0",
"eslint-plugin-filenames": "1.3.2",
"eslint-plugin-import": "2.29.1",
"eslint-plugin-json": "3.1.0",
"eslint-plugin-import": "2.31.0",
"eslint-plugin-prettier": "4.2.1",
"eslint-plugin-react": "7.34.1",
"eslint-plugin-react-hooks": "4.6.0",
"eslint-plugin-simple-import-sort": "12.1.0",
"eslint-plugin-react": "7.37.1",
"eslint-plugin-react-hooks": "4.6.2",
"eslint-plugin-simple-import-sort": "12.1.1",
"file-loader": "6.2.0",
"filemanager-webpack-plugin": "8.0.0",
"fork-ts-checker-webpack-plugin": "8.0.0",
"html-webpack-plugin": "5.5.3",
"html-webpack-plugin": "5.6.0",
"loader-utils": "^3.2.1",
"mini-css-extract-plugin": "2.7.6",
"postcss": "8.4.38",
"mini-css-extract-plugin": "2.9.1",
"postcss": "8.4.47",
"postcss-color-function": "4.1.0",
"postcss-loader": "7.3.0",
"postcss-mixins": "9.0.4",
"postcss-nested": "6.0.1",
"postcss-nested": "6.2.0",
"postcss-simple-vars": "7.0.1",
"postcss-url": "10.1.3",
"prettier": "2.8.8",
"require-nocache": "1.0.0",
"rimraf": "4.4.1",
"run-sequence": "2.2.1",
"streamqueue": "1.1.2",
"style-loader": "3.3.3",
"rimraf": "6.0.1",
"style-loader": "3.3.4",
"stylelint": "15.10.3",
"stylelint-order": "6.0.3",
"terser-webpack-plugin": "5.3.9",
"ts-loader": "9.4.4",
"stylelint-order": "6.0.4",
"terser-webpack-plugin": "5.3.10",
"ts-loader": "9.5.1",
"typescript-plugin-css-modules": "5.0.1",
"url-loader": "4.1.1",
"webpack": "5.88.2",
"webpack": "5.95.0",
"webpack-cli": "5.1.4",
"webpack-livereload-plugin": "3.0.2",
"worker-loader": "3.0.8"

View File

@@ -4,21 +4,22 @@
<PackageVersion Include="AutoFixture" Version="4.17.0" />
<PackageVersion Include="coverlet.collector" Version="3.0.4-preview.27.ge7cb7c3b40" PrivateAssets="all" />
<PackageVersion Include="Dapper" Version="2.0.151" />
<PackageVersion Include="Diacritical.Net" Version="1.0.4" />
<PackageVersion Include="DryIoc.dll" Version="5.4.3" />
<PackageVersion Include="DryIoc.Microsoft.DependencyInjection" Version="6.2.0" />
<PackageVersion Include="Equ" Version="2.3.0" />
<PackageVersion Include="FluentAssertions" Version="5.10.3" />
<PackageVersion Include="Polly" Version="8.4.1" />
<PackageVersion Include="Polly" Version="8.4.2" />
<PackageVersion Include="Servarr.FluentMigrator.Runner" Version="3.3.2.9" />
<PackageVersion Include="Servarr.FluentMigrator.Runner.SQLite" Version="3.3.2.9" />
<PackageVersion Include="Servarr.FluentMigrator.Runner.Postgres" Version="3.3.2.9" />
<PackageVersion Include="FluentValidation" Version="9.5.4" />
<PackageVersion Include="Ical.Net" Version="4.2.0" />
<PackageVersion Include="Ical.Net" Version="4.3.1" />
<PackageVersion Include="ImpromptuInterface" Version="7.0.1" />
<PackageVersion Include="LazyCache" Version="2.4.0" />
<PackageVersion Include="Mailkit" Version="3.6.0" />
<PackageVersion Include="Microsoft.AspNetCore.SignalR.Client" Version="6.0.32" />
<PackageVersion Include="Microsoft.Extensions.Caching.Memory" Version="6.0.1" />
<PackageVersion Include="Microsoft.AspNetCore.SignalR.Client" Version="6.0.35" />
<PackageVersion Include="Microsoft.Extensions.Caching.Memory" Version="6.0.2" />
<PackageVersion Include="Microsoft.Extensions.Configuration" Version="6.0.1" />
<PackageVersion Include="Microsoft.Extensions.DependencyInjection" Version="6.0.1" />
<PackageVersion Include="Microsoft.Extensions.Hosting.WindowsServices" Version="6.0.2" />
@@ -33,7 +34,7 @@
<PackageVersion Include="NLog.Extensions.Logging" Version="5.2.3" />
<PackageVersion Include="NLog" Version="5.1.4" />
<PackageVersion Include="NLog.Targets.Syslog" Version="7.0.0" />
<PackageVersion Include="Npgsql" Version="7.0.7" />
<PackageVersion Include="Npgsql" Version="7.0.8" />
<PackageVersion Include="NUnit3TestAdapter" Version="4.2.1" />
<PackageVersion Include="NUnit" Version="3.14.0" />
<PackageVersion Include="NunitXml.TestLogger" Version="3.0.117" />
@@ -61,8 +62,8 @@
<PackageVersion Include="System.Security.Principal.Windows" Version="5.0.0" />
<PackageVersion Include="System.ServiceProcess.ServiceController" Version="6.0.1" />
<PackageVersion Include="System.Text.Encoding.CodePages" Version="6.0.0" />
<PackageVersion Include="System.Text.Json" Version="6.0.9" />
<PackageVersion Include="System.Text.Json" Version="6.0.10" />
<PackageVersion Include="System.ValueTuple" Version="4.5.0" />
<PackageVersion Include="TagLibSharp-Lidarr" Version="2.2.0.19" />
</ItemGroup>
</Project>
</Project>

View File

@@ -89,6 +89,10 @@ namespace NzbDrone.Common.Test.InstrumentationTests
[TestCase(@"https://discord.com/api/webhooks/mySecret")]
[TestCase(@"https://discord.com/api/webhooks/mySecret/01233210")]
// Telegram
[TestCase(@"https://api.telegram.org/bot1234567890:mySecret/sendmessage: chat_id=123456&parse_mode=HTML&text=<text>")]
[TestCase(@"https://api.telegram.org/bot1234567890:mySecret/")]
public void should_clean_message(string message)
{
var cleansedMessage = CleanseLogMessage.Cleanse(message);

View File

@@ -54,7 +54,10 @@ namespace NzbDrone.Common.Instrumentation
new (@"api/v[0-9]/notification/readarr/(?<secret>[\w-]+)", RegexOptions.Compiled | RegexOptions.IgnoreCase),
// Discord
new (@"discord.com/api/webhooks/((?<secret>[\w-]+)/)?(?<secret>[\w-]+)", RegexOptions.Compiled | RegexOptions.IgnoreCase)
new (@"discord.com/api/webhooks/((?<secret>[\w-]+)/)?(?<secret>[\w-]+)", RegexOptions.Compiled | RegexOptions.IgnoreCase),
// Telegram
new (@"api.telegram.org/bot(?<id>[\d]+):(?<secret>[\w-]+)/", RegexOptions.Compiled | RegexOptions.IgnoreCase)
};
private static readonly Regex CleanseRemoteIPRegex = new (@"(?:Auth-\w+(?<!Failure|Unauthorized) ip|from) (\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})", RegexOptions.Compiled);

View File

@@ -49,10 +49,13 @@ namespace NzbDrone.Core.Test.Download.DownloadClientTests.TransmissionTests
}
[Test]
public void magnet_download_should_not_return_the_item()
public void magnet_download_should_be_returned_as_queued()
{
PrepareClientToReturnMagnetItem();
Subject.GetItems().Count().Should().Be(0);
var item = Subject.GetItems().Single();
item.Status.Should().Be(DownloadItemStatus.Queued);
}
[Test]

View File

@@ -60,7 +60,10 @@ namespace NzbDrone.Core.Test.Download.DownloadClientTests.VuzeTests
public void magnet_download_should_not_return_the_item()
{
PrepareClientToReturnMagnetItem();
Subject.GetItems().Count().Should().Be(0);
var item = Subject.GetItems().Single();
item.Status.Should().Be(DownloadItemStatus.Queued);
}
[Test]

View File

@@ -7,6 +7,7 @@ using NzbDrone.Core.HealthCheck.Checks;
using NzbDrone.Core.Localization;
using NzbDrone.Core.Test.Framework;
using NzbDrone.Core.Update;
using NzbDrone.Test.Common;
namespace NzbDrone.Core.Test.HealthCheck.Checks
{
@@ -21,28 +22,10 @@ namespace NzbDrone.Core.Test.HealthCheck.Checks
.Returns("Some Warning Message");
}
[Test]
public void should_return_error_when_app_folder_is_write_protected()
{
WindowsOnly();
Mocker.GetMock<IAppFolderInfo>()
.Setup(s => s.StartUpFolder)
.Returns(@"C:\NzbDrone");
Mocker.GetMock<IDiskProvider>()
.Setup(c => c.FolderWritable(It.IsAny<string>()))
.Returns(false);
Subject.Check().ShouldBeError();
}
[Test]
public void should_return_error_when_app_folder_is_write_protected_and_update_automatically_is_enabled()
{
PosixOnly();
const string startupFolder = @"/opt/nzbdrone";
var startupFolder = @"C:\NzbDrone".AsOsAgnostic();
Mocker.GetMock<IConfigFileProvider>()
.Setup(s => s.UpdateAutomatically)
@@ -62,10 +45,8 @@ namespace NzbDrone.Core.Test.HealthCheck.Checks
[Test]
public void should_return_error_when_ui_folder_is_write_protected_and_update_automatically_is_enabled()
{
PosixOnly();
const string startupFolder = @"/opt/nzbdrone";
const string uiFolder = @"/opt/nzbdrone/UI";
var startupFolder = @"C:\NzbDrone".AsOsAgnostic();
var uiFolder = @"C:\NzbDrone\UI".AsOsAgnostic();
Mocker.GetMock<IConfigFileProvider>()
.Setup(s => s.UpdateAutomatically)
@@ -89,7 +70,7 @@ namespace NzbDrone.Core.Test.HealthCheck.Checks
[Test]
public void should_not_return_error_when_app_folder_is_write_protected_and_external_script_enabled()
{
PosixOnly();
var startupFolder = @"C:\NzbDrone".AsOsAgnostic();
Mocker.GetMock<IConfigFileProvider>()
.Setup(s => s.UpdateAutomatically)
@@ -101,7 +82,7 @@ namespace NzbDrone.Core.Test.HealthCheck.Checks
Mocker.GetMock<IAppFolderInfo>()
.Setup(s => s.StartUpFolder)
.Returns(@"/opt/nzbdrone");
.Returns(startupFolder);
Mocker.GetMock<IDiskProvider>()
.Verify(c => c.FolderWritable(It.IsAny<string>()), Times.Never());

View File

@@ -13,7 +13,7 @@ using NzbDrone.Core.Test.Framework;
namespace NzbDrone.Core.Test.MetadataSource.Goodreads
{
[TestFixture]
[Ignore("Waiting for metadata to be back again", Until = "2024-08-15 00:00:00Z")]
[Ignore("Waiting for metadata to be back again", Until = "2024-12-15 00:00:00Z")]
public class BookInfoProxyFixture : CoreTest<BookInfoProxy>
{
private MetadataProfile _metadataProfile;

View File

@@ -15,7 +15,7 @@ using NzbDrone.Test.Common;
namespace NzbDrone.Core.Test.MetadataSource.Goodreads
{
[TestFixture]
[Ignore("Waiting for metadata to be back again", Until = "2024-08-15 00:00:00Z")]
[Ignore("Waiting for metadata to be back again", Until = "2024-12-15 00:00:00Z")]
public class BookInfoProxySearchFixture : CoreTest<BookInfoProxy>
{
[SetUp]

View File

@@ -255,7 +255,7 @@ namespace NzbDrone.Core.Configuration
public string UiFolder => BuildInfo.IsDebug ? Path.Combine("..", "UI") : "UI";
public string InstanceName => _appOptions.InstanceName ?? GetValue("InstanceName", BuildInfo.AppName);
public bool UpdateAutomatically => _updateOptions.Automatically ?? GetValueBoolean("UpdateAutomatically", false, false);
public bool UpdateAutomatically => _updateOptions.Automatically ?? GetValueBoolean("UpdateAutomatically", OsInfo.IsWindows, false);
public UpdateMechanism UpdateMechanism =>
Enum.TryParse<UpdateMechanism>(_updateOptions.Mechanism, out var enumValue)

View File

@@ -41,12 +41,6 @@ namespace NzbDrone.Core.Download.Clients.Transmission
foreach (var torrent in torrents)
{
// If totalsize == 0 the torrent is a magnet downloading metadata
if (torrent.TotalSize == 0)
{
continue;
}
var outputPath = new OsPath(torrent.DownloadDir);
if (Settings.TvDirectory.IsNotNullOrWhiteSpace())
@@ -97,6 +91,10 @@ namespace NzbDrone.Core.Download.Clients.Transmission
item.Status = DownloadItemStatus.Warning;
item.Message = torrent.ErrorString;
}
else if (torrent.TotalSize == 0)
{
item.Status = DownloadItemStatus.Queued;
}
else if (torrent.LeftUntilDone == 0 && (torrent.Status == TransmissionTorrentStatus.Stopped ||
torrent.Status == TransmissionTorrentStatus.Seeding ||
torrent.Status == TransmissionTorrentStatus.SeedingWait))

View File

@@ -39,7 +39,7 @@ namespace NzbDrone.Core.HealthCheck.Checks
var startupFolder = _appFolderInfo.StartUpFolder;
var uiFolder = Path.Combine(startupFolder, "UI");
if ((OsInfo.IsWindows || _configFileProvider.UpdateAutomatically) &&
if (_configFileProvider.UpdateAutomatically &&
_configFileProvider.UpdateMechanism == UpdateMechanism.BuiltIn &&
!_osInfo.IsDocker)
{

View File

@@ -3,8 +3,8 @@
"Year": "عام",
"WeekColumnHeader": "رأس عمود الأسبوع",
"Version": "الإصدار",
"UsingExternalUpdateMechanismBranchUsedByExternalUpdateMechanism": "يستخدم الفرع بواسطة آلية التحديث الخارجية",
"UsingExternalUpdateMechanismBranchToUseToUpdateReadarr": "فرع لاستخدامه لتحديث Radarr",
"BranchUpdateMechanism": "يستخدم الفرع بواسطة آلية التحديث الخارجية",
"BranchUpdate": "فرع لاستخدامه لتحديث Radarr",
"Username": "اسم المستخدم",
"UsenetDelayHelpText": "تأخر بالدقائق للانتظار قبل الحصول على إصدار من Usenet",
"UsenetDelay": "تأخير يوزنت",
@@ -300,7 +300,7 @@
"ChangeFileDate": "تغيير تاريخ الملف",
"CertificateValidationHelpText": "تغيير مدى صرامة التحقق من صحة شهادة HTTPS",
"CertificateValidation": "التحقق من صحة الشهادة",
"CancelMessageText": "هل أنت متأكد أنك تريد إلغاء هذه المهمة المعلقة؟",
"CancelPendingTask": "هل أنت متأكد أنك تريد إلغاء هذه المهمة المعلقة؟",
"Cancel": "إلغاء",
"CalendarWeekColumnHeaderHelpText": "يظهر فوق كل عمود عندما يكون الأسبوع هو العرض النشط",
"Calendar": "التقويم",

View File

@@ -36,7 +36,7 @@
"Calendar": "Календар",
"CalendarWeekColumnHeaderHelpText": "Показва се над всяка колона, когато седмицата е активният изглед",
"Cancel": "Отказ",
"CancelMessageText": "Наистина ли искате да отмените тази чакаща задача?",
"CancelPendingTask": "Наистина ли искате да отмените тази чакаща задача?",
"CertificateValidation": "Валидиране на сертификат",
"CertificateValidationHelpText": "Променете колко строго е валидирането на HTTPS сертифициране",
"ChangeFileDate": "Промяна на датата на файла",
@@ -422,8 +422,8 @@
"UsenetDelay": "Usenet Delay",
"UsenetDelayHelpText": "Забавете за минути, за да изчакате, преди да вземете съобщение от Usenet",
"Username": "Потребителско име",
"UsingExternalUpdateMechanismBranchToUseToUpdateReadarr": "Клон, който да се използва за актуализиране на Radarr",
"UsingExternalUpdateMechanismBranchUsedByExternalUpdateMechanism": "Клон, използван от външен механизъм за актуализация",
"BranchUpdate": "Клон, който да се използва за актуализиране на Radarr",
"BranchUpdateMechanism": "Клон, използван от външен механизъм за актуализация",
"Version": "Версия",
"WeekColumnHeader": "Заглавка на колоната на седмицата",
"Year": "Година",

View File

@@ -445,7 +445,7 @@
"ApplicationURL": "URL de l'aplicació",
"ApplicationUrlHelpText": "URL extern de l'aplicació, inclòs http(s)://, port i URL base",
"BackupFolderHelpText": "Els camins relatius estaran sota el directori AppData del Radarr",
"CancelMessageText": "Esteu segur que voleu cancel·lar aquesta tasca pendent?",
"CancelPendingTask": "Esteu segur que voleu cancel·lar aquesta tasca pendent?",
"ChownGroupHelpTextWarning": "Això només funciona si l'usuari que executa Radarr és el propietari del fitxer. És millor assegurar-se que el client de descàrrega utilitza el mateix grup que Radarr.",
"ConnectSettingsSummary": "Notificacions, connexions a servidors/reproductors multimèdia i scripts personalitzats",
"DeleteEmptyFoldersHelpText": "Suprimeix les carpetes de pel·lícules buides durant l'exploració del disc i quan s'esborren els fitxers de pel·lícules",
@@ -487,9 +487,9 @@
"SuccessMyWorkIsDoneNoFilesToRetag": "Èxit! La feina està acabada, no hi ha fitxers per canviar el nom.",
"TimeLeft": "Temps restant",
"UnableToLoadImportListExclusions": "No es poden carregar les exclusions de la llista",
"UsingExternalUpdateMechanismBranchToUseToUpdateReadarr": "Branca que s'utilitza per actualitzar Radarr",
"BranchUpdate": "Branca que s'utilitza per actualitzar Radarr",
"UserAgentProvidedByTheAppThatCalledTheAPI": "Agent d'usuari proporcionat per l'aplicació per fer peticions a l'API",
"UsingExternalUpdateMechanismBranchUsedByExternalUpdateMechanism": "Branca utilitzada pel mecanisme d'actualització extern",
"BranchUpdateMechanism": "Branca utilitzada pel mecanisme d'actualització extern",
"WriteTagsNo": "Mai",
"RestartReloadNote": "Nota: Radarr es reiniciarà i tornarà a carregar automàticament la interfície d'usuari durant el procés de restauració.",
"Series": "Sèries",

View File

@@ -41,7 +41,7 @@
"Calendar": "Kalendář",
"CalendarWeekColumnHeaderHelpText": "Zobrazuje se nad každým sloupcem, když je aktivní zobrazení týden",
"Cancel": "Zrušit",
"CancelMessageText": "Opravdu chcete zrušit tento nevyřízený úkol?",
"CancelPendingTask": "Opravdu chcete zrušit tento nevyřízený úkol?",
"CertificateValidation": "Ověření certifikátu",
"CertificateValidationHelpText": "Změňte přísnost ověřování certifikátů HTTPS. Neměňte, pokud nerozumíte rizikům.",
"ChangeFileDate": "Změnit datum souboru",
@@ -429,8 +429,8 @@
"UsenetDelay": "Usenet Zpoždění",
"UsenetDelayHelpText": "Zpoždění v minutách čekání před uvolněním z Usenetu",
"Username": "Uživatelské jméno",
"UsingExternalUpdateMechanismBranchToUseToUpdateReadarr": "Pobočka, která se má použít k aktualizaci Radarr",
"UsingExternalUpdateMechanismBranchUsedByExternalUpdateMechanism": "Pobočka používaná mechanismem externí aktualizace",
"BranchUpdate": "Pobočka, která se má použít k aktualizaci Radarr",
"BranchUpdateMechanism": "Pobočka používaná mechanismem externí aktualizace",
"Version": "Verze",
"WeekColumnHeader": "Záhlaví sloupce týdne",
"Year": "Rok",

View File

@@ -38,7 +38,7 @@
"Calendar": "Kalender",
"CalendarWeekColumnHeaderHelpText": "Vist over hver kolonne, når ugen er den aktive visning",
"Cancel": "Afbryd",
"CancelMessageText": "Er du sikker på, at du vil annullere denne afventende opgave?",
"CancelPendingTask": "Er du sikker på, at du vil annullere denne afventende opgave?",
"CertificateValidation": "Validering af certifikat",
"CertificateValidationHelpText": "Skift, hvor streng HTTPS-certificering er",
"ChangeFileDate": "Skift fildato",
@@ -424,8 +424,8 @@
"UsenetDelay": "Usenet-forsinkelse",
"UsenetDelayHelpText": "Forsink i minutter, før du tager fat i en frigivelse fra Usenet",
"Username": "Brugernavn",
"UsingExternalUpdateMechanismBranchToUseToUpdateReadarr": "Filial, der skal bruges til at opdatere Radarr",
"UsingExternalUpdateMechanismBranchUsedByExternalUpdateMechanism": "Gren brugt af ekstern opdateringsmekanisme",
"BranchUpdate": "Filial, der skal bruges til at opdatere Radarr",
"BranchUpdateMechanism": "Gren brugt af ekstern opdateringsmekanisme",
"Version": "Version",
"WeekColumnHeader": "Ugens kolonneoverskrift",
"Year": "År",

View File

@@ -35,7 +35,7 @@
"Calendar": "Kalender",
"CalendarWeekColumnHeaderHelpText": "Wird in der Wochenansicht über jeder Spalte angezeigt",
"Cancel": "Abbrechen",
"CancelMessageText": "Diese laufende Aufgabe wirklich abbrechen?",
"CancelPendingTask": "Diese laufende Aufgabe wirklich abbrechen?",
"CertificateValidation": "Zertifikatsvalidierung",
"CertificateValidationHelpText": "Ändern Sie, wie streng die Validierung der HTTPS-Zertifizierung ist. Ändern Sie nichts, es sei denn, Sie verstehen die Risiken.",
"ChangeFileDate": "Ändern Sie das Dateidatum",
@@ -415,8 +415,8 @@
"UsenetDelay": "Usenet-Verzögerung",
"UsenetDelayHelpText": "Verzögerung in Minuten, bevor Sie eine Veröffentlichung aus dem Usenet erhalten",
"Username": "Nutzername",
"UsingExternalUpdateMechanismBranchToUseToUpdateReadarr": "Branch zum updaten von Radarr",
"UsingExternalUpdateMechanismBranchUsedByExternalUpdateMechanism": "Branch für den externen Updateablauf",
"BranchUpdate": "Branch zum updaten von Radarr",
"BranchUpdateMechanism": "Branch für den externen Updateablauf",
"Version": "Version",
"WeekColumnHeader": "Spaltenüberschrift „Woche“.",
"Year": "Jahr",

View File

@@ -40,7 +40,7 @@
"Calendar": "Ημερολόγιο",
"CalendarWeekColumnHeaderHelpText": "Εμφανίζεται πάνω από κάθε στήλη όταν η εβδομάδα είναι η ενεργή προβολή",
"Cancel": "Ακύρωση",
"CancelMessageText": "Είστε βέβαιοι ότι θέλετε να ακυρώσετε αυτήν την εργασία σε εκκρεμότητα;",
"CancelPendingTask": "Είστε βέβαιοι ότι θέλετε να ακυρώσετε αυτήν την εργασία σε εκκρεμότητα;",
"CertificateValidation": "Επικύρωση πιστοποιητικού",
"CertificateValidationHelpText": "Αλλάξτε πόσο αυστηρή είναι η επικύρωση πιστοποίησης HTTPS.",
"ChangeFileDate": "Αλλαγή ημερομηνίας αρχείου",
@@ -424,8 +424,8 @@
"UsenetDelay": "Καθυστέρηση Usenet",
"UsenetDelayHelpText": "Καθυστέρηση σε λίγα λεπτά για να περιμένετε πριν πάρετε μια κυκλοφορία από το Usenet",
"Username": "Όνομα χρήστη",
"UsingExternalUpdateMechanismBranchToUseToUpdateReadarr": "Υποκατάστημα για χρήση για την ενημέρωση του Radarr",
"UsingExternalUpdateMechanismBranchUsedByExternalUpdateMechanism": "Υποκατάστημα που χρησιμοποιείται από εξωτερικό μηχανισμό ενημέρωσης",
"BranchUpdate": "Υποκατάστημα για χρήση για την ενημέρωση του Radarr",
"BranchUpdateMechanism": "Υποκατάστημα που χρησιμοποιείται από εξωτερικό μηχανισμό ενημέρωσης",
"Version": "Εκδοχή",
"WeekColumnHeader": "Κεφαλίδα στήλης εβδομάδας",
"Year": "Ετος",

View File

@@ -49,6 +49,7 @@
"ApplyTagsHelpTextHowToApplyIndexers": "How to apply tags to the selected indexers",
"ApplyTagsHelpTextRemove": "Remove: Remove the entered tags",
"ApplyTagsHelpTextReplace": "Replace: Replace the tags with the entered tags (enter no tags to clear all tags)",
"AptUpdater": "Use apt to install the update",
"AudioFileMetadata": "Write Metadata to Audio Files",
"AuthBasic": "Basic (Browser Popup)",
"AuthForm": "Forms (Login Page)",
@@ -116,6 +117,9 @@
"BooksTotal": "Books ({0})",
"Bookshelf": "Bookshelf",
"Branch": "Branch",
"BranchUpdate": "Branch to use to update {appName}",
"BranchUpdateMechanism": "Branch used by external update mechanism",
"BuiltIn": "Built-In",
"BypassIfAboveCustomFormatScore": "Bypass if Above Custom Format Score",
"BypassIfAboveCustomFormatScoreHelpText": "Enable bypass when release has a score higher than the configured minimum custom format score",
"BypassIfHighestQuality": "Bypass if Highest Quality",
@@ -137,7 +141,7 @@
"CalibreUrlBase": "Calibre Url Base",
"CalibreUsername": "Calibre Username",
"Cancel": "Cancel",
"CancelMessageText": "Are you sure you want to cancel this pending task?",
"CancelPendingTask": "Are you sure you want to cancel this pending task?",
"CatalogNumber": "Catalog Number",
"CertificateValidation": "Certificate Validation",
"CertificateValidationHelpText": "Change how strict HTTPS certification validation is. Do not change unless you understand the risks.",
@@ -197,6 +201,7 @@
"CreateEmptyAuthorFolders": "Create empty author folders",
"CreateEmptyAuthorFoldersHelpText": "Create missing author folders during disk scan",
"CreateGroup": "Create group",
"CurrentlyInstalled": "Currently Installed",
"CustomFilter": "Custom Filter",
"CustomFormat": "Custom Format",
"CustomFormatScore": "Custom Format Score",
@@ -293,6 +298,7 @@
"DoNotBlocklist": "Do not Blocklist",
"DoNotBlocklistHint": "Remove without blocklisting",
"Docker": "Docker",
"DockerUpdater": "Update the docker container to receive the update",
"DownloadClient": "Download Client",
"DownloadClientCheckDownloadingToRoot": "Download client {0} places downloads in the root folder {1}. You should not download to a root folder.",
"DownloadClientCheckNoneAvailableMessage": "No download client is available",
@@ -357,10 +363,13 @@
"ExistingTagsScrubbed": "Existing tags scrubbed",
"ExportCustomFormat": "Export Custom Format",
"External": "External",
"ExternalUpdater": "{appName} is configured to use an external update mechanism",
"ExtraFileExtensionsHelpText": "Comma separated list of extra files to import (.nfo will be imported as .nfo-orig)",
"ExtraFileExtensionsHelpTextsExamples": "Examples: '.sub, .nfo' or 'sub,nfo'",
"FailedDownloadHandling": "Failed Download Handling",
"FailedLoadingSearchResults": "Failed to load search results, please try again.",
"FailedToFetchSettings": "Failed to fetch settings",
"FailedToFetchUpdates": "Failed to fetch updates",
"FailedToLoadQueue": "Failed to load Queue",
"FileDateHelpText": "Change file date on import/rescan",
"FileDetails": "File Details",
@@ -478,6 +487,11 @@
"IndexerTagsHelpText": "Only use this indexer for authors with at least one matching tag. Leave blank to use with all authors.",
"Indexers": "Indexers",
"IndexersSettingsSummary": "Indexers and release restrictions",
"Install": "Install",
"InstallLatest": "Install Latest",
"InstallMajorVersionUpdate": "Install Update",
"InstallMajorVersionUpdateMessage": "This update will install a new major version and may not be compatible with your system. Are you sure you want to install this update?",
"InstallMajorVersionUpdateMessageLink": "Please check [{domain}]({url}) for more information.",
"InstanceName": "Instance Name",
"InstanceNameHelpText": "Instance name in tab and for Syslog app name",
"InteractiveSearchModalHeader": "Interactive Search",
@@ -674,6 +688,7 @@
"OnHealthIssueHelpText": "On Health Issue",
"OnImportFailure": "On Import Failure",
"OnImportFailureHelpText": "On Import Failure",
"OnLatestVersion": "The latest version of {appName} is already installed",
"OnReleaseImport": "On Release Import",
"OnReleaseImportHelpText": "On Release Import",
"OnRename": "On Rename",
@@ -706,6 +721,7 @@
"PosterSize": "Poster Size",
"PreviewRename": "Preview Rename",
"PreviewRetag": "Preview Retag",
"PreviouslyInstalled": "Previously Installed",
"Profiles": "Profiles",
"ProfilesSettingsSummary": "Quality, Metadata, Delay, and Release profiles",
"Progress": "Progress",
@@ -858,6 +874,7 @@
"SSLPort": "SSL Port",
"Save": "Save",
"Scheduled": "Scheduled",
"Script": "Script",
"ScriptPath": "Script Path",
"Search": "Search",
"SearchAll": "Search All",
@@ -1051,6 +1068,7 @@
"UnmonitoredHelpText": "Include unmonitored books in the iCal feed",
"UnselectAll": "Unselect All",
"UpdateAll": "Update all",
"UpdateAppDirectlyLoadError": "Unable to update {appName} directly,",
"UpdateAutomaticallyHelpText": "Automatically download and install updates. You will still be able to install from System: Updates",
"UpdateAvailable": "New update is available",
"UpdateCheckStartupNotWritableMessage": "Cannot install update because startup folder '{0}' is not writable by the user '{1}'.",
@@ -1079,8 +1097,6 @@
"UserAgentProvidedByTheAppThatCalledTheAPI": "User-Agent provided by the app that called the API",
"Username": "Username",
"UsernameHelpText": "Calibre content server username",
"UsingExternalUpdateMechanismBranchToUseToUpdateReadarr": "Branch to use to update Readarr",
"UsingExternalUpdateMechanismBranchUsedByExternalUpdateMechanism": "Branch used by external update mechanism",
"Version": "Version",
"Wanted": "Wanted",
"WatchLibraryForChangesHelpText": "Rescan automatically when files change in a root folder",

View File

@@ -42,7 +42,7 @@
"Calendar": "Calendario",
"CalendarWeekColumnHeaderHelpText": "Mostrado sobre cada columna cuando la vista activa es semana",
"Cancel": "Cancelar",
"CancelMessageText": "Seguro que quieres cancelar esta tarea pendiente?",
"CancelPendingTask": "Seguro que quieres cancelar esta tarea pendiente?",
"CertificateValidation": "Validacion de certificado",
"CertificateValidationHelpText": "Cambia cómo de estricta es la validación de certificación de HTTPS. No cambiar a menos que entiendas los riesgos.",
"ChangeFileDate": "Cambiar fecha de archivo",
@@ -423,8 +423,8 @@
"UsenetDelay": "Retraso de usenet",
"UsenetDelayHelpText": "Retraso en minutos a esperar antes de capturar un lanzamiento desde usenet",
"Username": "Usuario",
"UsingExternalUpdateMechanismBranchToUseToUpdateReadarr": "Rama a utilizar para actualizar Readarr",
"UsingExternalUpdateMechanismBranchUsedByExternalUpdateMechanism": "Rama usada por el mecanismo de actualización externo",
"BranchUpdate": "Rama a utilizar para actualizar Readarr",
"BranchUpdateMechanism": "Rama usada por el mecanismo de actualización externo",
"Version": "Versión",
"WeekColumnHeader": "Cabecera de columna de semana",
"Year": "Año",

View File

@@ -38,7 +38,7 @@
"Calendar": "Kalenteri",
"CalendarWeekColumnHeaderHelpText": "Näkyy jokaisen sarakkeen yläpuolella käytettäessä viikkonäkymää.",
"Cancel": "Peruuta",
"CancelMessageText": "Haluatko varmasti perua tämän odottavan tehtävän?",
"CancelPendingTask": "Haluatko varmasti perua tämän odottavan tehtävän?",
"CertificateValidation": "Varmenteen vahvistus",
"CertificateValidationHelpText": "Määritä HTTPS-varmennevahvistuksen tiukkuus. Älä muta, jos et ymmärrä riskejä.",
"ChangeFileDate": "Muuta tiedoston päiväys",
@@ -424,8 +424,8 @@
"UsenetDelay": "Usenet-viive",
"UsenetDelayHelpText": "Minuuttiviive, joka odotetaan ennen julkaisun Usenet-kaappausta.",
"Username": "Käyttäjätunnus",
"UsingExternalUpdateMechanismBranchToUseToUpdateReadarr": "Sovelluksen versiopäivityksiin käytettävä kehityshaara.",
"UsingExternalUpdateMechanismBranchUsedByExternalUpdateMechanism": "Ulkoisen päivitysratkaisun käyttämä kehityshaara.",
"BranchUpdate": "Sovelluksen versiopäivityksiin käytettävä kehityshaara.",
"BranchUpdateMechanism": "Ulkoisen päivitysratkaisun käyttämä kehityshaara.",
"Version": "Versio",
"WeekColumnHeader": "Viikkosarakkeen otsikko",
"Year": "Vuosi",

View File

@@ -48,7 +48,7 @@
"Calendar": "Calendrier",
"CalendarWeekColumnHeaderHelpText": "Affiché au dessus de chaque colonne quand \"Semaine\" est l'affichage actif",
"Cancel": "Annuler",
"CancelMessageText": "Êtes-vous sur de vouloir annuler cette tâche en attente ?",
"CancelPendingTask": "Êtes-vous sur de vouloir annuler cette tâche en attente ?",
"CertificateValidation": "Validation du certificat",
"CertificateValidationHelpText": "Modifier le niveau de rigueur de la validation de la certification HTTPS. Ne pas modifier si vous ne maîtrisez pas les risques.",
"ChangeFileDate": "Changer la date du fichier",
@@ -429,8 +429,8 @@
"UsenetDelay": "Retard Usenet",
"UsenetDelayHelpText": "Délai en minutes avant de récupérer une release de Usenet",
"Username": "Nom d'utilisateur",
"UsingExternalUpdateMechanismBranchToUseToUpdateReadarr": "Branche à utiliser pour mettre à jour Readarr",
"UsingExternalUpdateMechanismBranchUsedByExternalUpdateMechanism": "Branche utilisée par le mécanisme de mise à jour extérieur",
"BranchUpdate": "Branche à utiliser pour mettre à jour Readarr",
"BranchUpdateMechanism": "Branche utilisée par le mécanisme de mise à jour extérieur",
"Version": "Version",
"WeekColumnHeader": "En-tête de colonne de la semaine",
"Year": "Année",

View File

@@ -25,7 +25,7 @@
"BypassProxyForLocalAddresses": "עקיפת פרוקסי לכתובות מקומיות",
"Calendar": "לוּחַ שָׁנָה",
"CalendarWeekColumnHeaderHelpText": "מוצג מעל כל עמודה כאשר השבוע היא התצוגה הפעילה",
"CancelMessageText": "האם אתה בטוח שברצונך לבטל משימה זו בהמתנה?",
"CancelPendingTask": "האם אתה בטוח שברצונך לבטל משימה זו בהמתנה?",
"CertificateValidation": "אימות תעודה",
"CertificateValidationHelpText": "שנה את מידת אימות ההסמכה של HTTPS",
"ChangeFileDate": "שנה את תאריך הקובץ",
@@ -411,8 +411,8 @@
"UsenetDelay": "עיכוב Usenet",
"UsenetDelayHelpText": "עיכוב תוך דקות להמתין לפני שתופס שחרור מאוסנט",
"Username": "שם משתמש",
"UsingExternalUpdateMechanismBranchToUseToUpdateReadarr": "ענף לשימוש עדכון Radarr",
"UsingExternalUpdateMechanismBranchUsedByExternalUpdateMechanism": "ענף המשמש את מנגנון העדכון החיצוני",
"BranchUpdate": "ענף לשימוש עדכון Radarr",
"BranchUpdateMechanism": "ענף המשמש את מנגנון העדכון החיצוני",
"Version": "גִרְסָה",
"WeekColumnHeader": "כותרת עמודות שבוע",
"Year": "שָׁנָה",

View File

@@ -31,7 +31,7 @@
"Calendar": "पंचांग",
"CalendarWeekColumnHeaderHelpText": "प्रत्येक स्तंभ के ऊपर दिखाया गया जब सप्ताह सक्रिय दृश्य होता है",
"Cancel": "रद्द करना",
"CancelMessageText": "क्या आप वाकई इस लंबित कार्य को रद्द करना चाहते हैं?",
"CancelPendingTask": "क्या आप वाकई इस लंबित कार्य को रद्द करना चाहते हैं?",
"CertificateValidation": "प्रमाणपत्र सत्यापन",
"CertificateValidationHelpText": "बदलें कि HTTPS प्रमाणन सत्यापन कितना सख्त है",
"ChangeFileDate": "फ़ाइल दिनांक बदलें",
@@ -417,8 +417,8 @@
"UsenetDelay": "यूज़नेट देरी",
"UsenetDelayHelpText": "यूज़नेट से एक रिलीज हथियाने से पहले इंतजार करने के लिए मिनटों में देरी",
"Username": "उपयोगकर्ता नाम",
"UsingExternalUpdateMechanismBranchToUseToUpdateReadarr": "रेडर को अपडेट करने के लिए उपयोग करने के लिए शाखा",
"UsingExternalUpdateMechanismBranchUsedByExternalUpdateMechanism": "बाहरी अद्यतन तंत्र द्वारा उपयोग की जाने वाली शाखा",
"BranchUpdate": "रेडर को अपडेट करने के लिए उपयोग करने के लिए शाखा",
"BranchUpdateMechanism": "बाहरी अद्यतन तंत्र द्वारा उपयोग की जाने वाली शाखा",
"Version": "संस्करण",
"WeekColumnHeader": "वीक कॉलम हैडर",
"Year": "साल",

View File

@@ -125,7 +125,7 @@
"AutoUnmonitorPreviouslyDownloadedBooksHelpText": "U Radarru se automatski isključuje nadzor za filmove koji su izbrisani sa diska",
"BackupFolderHelpText": "Relativne putanje će biti unutar Radarrovog AppData direktorija",
"BypassIfHighestQuality": "Zaobiđi ako je Najviši Kvalitet",
"CancelMessageText": "Jeste li sigurni da želite otkazati ovaj zadatak na čekanju?",
"CancelPendingTask": "Jeste li sigurni da želite otkazati ovaj zadatak na čekanju?",
"ChmodFolderHelpTextWarning": "Ovo jedino radi ako je korisnik koji je pokrenuo Radarr vlasnik datoteke. Bolje je osigurati da klijent za preuzimanje postavi dozvolu ispravno.",
"ChownGroupHelpTextWarning": "Ovo jedino radi ako je korisnik koji je pokrenuo Radarr vlasnik datoteke. Bolje je osigurati da klijent za preuzimanje koristi istu grupu kao Radarr.",
"DeleteImportListMessageText": "Jeste li sigurni da želite obrisati oznaku formata {0}?",
@@ -134,8 +134,8 @@
"DeleteNotificationMessageText": "Jeste li sigurni da želite obrisati oznaku formata {0}?",
"DeleteQualityProfileMessageText": "Jeste li sigurni da želite obrisati ovaj profil odgode?",
"DeleteRootFolderMessageText": "Jeste li sigurni da želite obrisati oznaku formata {0}?",
"UsingExternalUpdateMechanismBranchToUseToUpdateReadarr": "Grana korištena za ažuriranje Radarra",
"UsingExternalUpdateMechanismBranchUsedByExternalUpdateMechanism": "Grana korištena od strane vanjskog mehanizma za ažuriranje",
"BranchUpdate": "Grana korištena za ažuriranje Radarra",
"BranchUpdateMechanism": "Grana korištena od strane vanjskog mehanizma za ažuriranje",
"ColonReplacement": "Zamjena Zareza",
"DeleteRemotePathMapping": "Daljinsko Mapiranje Portova",
"BlocklistReleaseHelpText": "Spriječi Radarr da automatski dohvaća ovu verziju ponovno",

View File

@@ -24,7 +24,7 @@
"Calendar": "Naptár",
"CalendarWeekColumnHeaderHelpText": "Minden oszlop felett jelenjen meg, hogy melyik hét az aktuális",
"Cancel": "Mégse",
"CancelMessageText": "Biztosan törlöd ezt a függőben lévő feladatot?",
"CancelPendingTask": "Biztosan törlöd ezt a függőben lévő feladatot?",
"CertificateValidation": "Tanúsítvány érvényesítése",
"CertificateValidationHelpText": "Módosítsa a HTTPS-tanúsítvány-ellenőrzés szigorúságát. Ne változtasson, hacsak nem érti a kockázatokat.",
"ChangeFileDate": "Fájl dátumának módosítása",
@@ -422,8 +422,8 @@
"UsenetDelay": "Usenet késleltetés",
"UsenetDelayHelpText": "Időeltolás percekben, mielőtt megkaparintana egy Usenet kiadást",
"Username": "Felhasználónév",
"UsingExternalUpdateMechanismBranchToUseToUpdateReadarr": "Ágazattípus a Radarr frissítéseihez",
"UsingExternalUpdateMechanismBranchUsedByExternalUpdateMechanism": "A külső frissítési mechanizmus által használt ágazat",
"BranchUpdate": "Ágazattípus a Radarr frissítéseihez",
"BranchUpdateMechanism": "A külső frissítési mechanizmus által használt ágazat",
"Version": "Verzió",
"WeekColumnHeader": "Heti oszlopfejléc",
"Year": "Év",

View File

@@ -44,7 +44,7 @@
"Calendar": "Dagatal",
"CalendarWeekColumnHeaderHelpText": "Sýnt fyrir ofan hvern dálk þegar vikan er virka skjámyndin",
"Cancel": "Hætta við",
"CancelMessageText": "Ertu viss um að þú viljir hætta við þetta verkefni í bið?",
"CancelPendingTask": "Ertu viss um að þú viljir hætta við þetta verkefni í bið?",
"CertificateValidation": "Staðfesting skírteina",
"CertificateValidationHelpText": "Breyttu hversu ströng HTTPS vottun er",
"ChangeFileDate": "Breyttu dagsetningu skráar",
@@ -429,8 +429,8 @@
"UsenetDelay": "Seinkun Usenet",
"UsenetDelayHelpText": "Seinkaðu í nokkrar mínútur til að bíða áður en þú grípur losun frá Usenet",
"Username": "Notendanafn",
"UsingExternalUpdateMechanismBranchToUseToUpdateReadarr": "Útibú til að nota til að uppfæra Radarr",
"UsingExternalUpdateMechanismBranchUsedByExternalUpdateMechanism": "Útibú notað af ytri uppfærslu",
"BranchUpdate": "Útibú til að nota til að uppfæra Radarr",
"BranchUpdateMechanism": "Útibú notað af ytri uppfærslu",
"Version": "Útgáfa",
"WeekColumnHeader": "Haus vikudálkur",
"Year": "Ár",

View File

@@ -16,8 +16,8 @@
"UsenetDelay": "Ritardo della Usenet",
"UsenetDelayHelpText": "Minuti di attesa prima di prendere una release da Usenet",
"Username": "Nome Utente",
"UsingExternalUpdateMechanismBranchToUseToUpdateReadarr": "Branch da utilizzare per aggiornare Radarr",
"UsingExternalUpdateMechanismBranchUsedByExternalUpdateMechanism": "Ramo utilizzato dal sistema di aggiornamento esterno",
"BranchUpdate": "Branch da utilizzare per aggiornare Radarr",
"BranchUpdateMechanism": "Ramo utilizzato dal sistema di aggiornamento esterno",
"Version": "Versione",
"WeekColumnHeader": "Intestazione colonna settimana",
"Year": "Anno",
@@ -48,7 +48,7 @@
"Calendar": "Calendario",
"CalendarWeekColumnHeaderHelpText": "Mostra sopra ogni colonna quando la settimana è la vista attiva",
"Cancel": "Annulla",
"CancelMessageText": "Sei sicuro di voler cancellare questa operazione in sospeso?",
"CancelPendingTask": "Sei sicuro di voler cancellare questa operazione in sospeso?",
"CertificateValidation": "Convalida del Certificato",
"CertificateValidationHelpText": "Cambia quanto rigorosamente vengono validati i certificati HTTPS. Non cambiare senza conoscerne i rischi.",
"ChangeFileDate": "Cambiare la Data del File",

View File

@@ -349,7 +349,7 @@
"Calendar": "カレンダー",
"CalendarWeekColumnHeaderHelpText": "週がアクティブビューの場合、各列の上に表示されます",
"Cancel": "キャンセル",
"CancelMessageText": "この保留中のタスクをキャンセルしてもよろしいですか?",
"CancelPendingTask": "この保留中のタスクをキャンセルしてもよろしいですか?",
"CertificateValidation": "証明書の検証",
"CertificateValidationHelpText": "HTTPS認証検証の厳密さを変更する",
"ChangeFileDate": "ファイルの日付を変更する",
@@ -429,8 +429,8 @@
"UsenetDelay": "Usenet遅延",
"UsenetDelayHelpText": "Usenetからリリースを取得する前に待機するために数分遅れます",
"Username": "ユーザー名",
"UsingExternalUpdateMechanismBranchToUseToUpdateReadarr": "Radarrの更新に使用するブランチ",
"UsingExternalUpdateMechanismBranchUsedByExternalUpdateMechanism": "外部更新メカニズムで使用されるブランチ",
"BranchUpdate": "Radarrの更新に使用するブランチ",
"BranchUpdateMechanism": "外部更新メカニズムで使用されるブランチ",
"Version": "バージョン",
"WeekColumnHeader": "週の列ヘッダー",
"Year": "年",

View File

@@ -88,7 +88,7 @@
"Calendar": "달력",
"CalendarWeekColumnHeaderHelpText": "주가 활성보기 일 때 각 열 위에 표시됩니다.",
"Cancel": "취소",
"CancelMessageText": "이 보류중인 작업을 취소 하시겠습니까?",
"CancelPendingTask": "이 보류중인 작업을 취소 하시겠습니까?",
"CertificateValidation": "인증서 검증",
"CertificateValidationHelpText": "HTTPS 인증 유효성 검사의 엄격한 방법 변경",
"ChangeFileDate": "파일 날짜 변경",
@@ -423,8 +423,8 @@
"UsenetDelay": "유즈넷 지연",
"UsenetDelayHelpText": "Usenet에서 릴리스를 가져 오기 전에 대기하는 데 몇 분 지연",
"Username": "사용자 이름",
"UsingExternalUpdateMechanismBranchToUseToUpdateReadarr": "Radarr 업데이트에 사용할 분기",
"UsingExternalUpdateMechanismBranchUsedByExternalUpdateMechanism": "외부 업데이트 메커니즘에서 사용하는 분기",
"BranchUpdate": "Radarr 업데이트에 사용할 분기",
"BranchUpdateMechanism": "외부 업데이트 메커니즘에서 사용하는 분기",
"Version": "버전",
"WeekColumnHeader": "주 열 헤더",
"YesCancel": "예, 취소합니다",

View File

@@ -28,7 +28,7 @@
"BindAddressHelpText": "Gyldig IPv4 -adresse, localhost eller \"*\" for alle grensesnitt",
"BypassProxyForLocalAddresses": "Omgå proxy for lokale adresser",
"Cancel": "Avbryt",
"CancelMessageText": "Er du sikker på at du vil avbryte denne ventende oppgaven?",
"CancelPendingTask": "Er du sikker på at du vil avbryte denne ventende oppgaven?",
"CertificateValidation": "Sertifikatvalidering",
"CertificateValidationHelpText": "Endre hvor streng HTTPS -sertifisering validering er. Ikke endre med mindre du forstår risikoene.",
"ChangeHasNotBeenSavedYet": "Endringen er ikke lagret ennå",
@@ -43,8 +43,8 @@
"DeleteTagMessageText": "Er du sikker på at du vil slette formattaggen {0}?",
"ResetAPIKeyMessageText": "Er du sikker på at du vil tilbakestille API -nøkkelen din?",
"ShowQualityProfile": "Legg til kvalitetsprofil",
"UsingExternalUpdateMechanismBranchToUseToUpdateReadarr": "Gren som skal brukes til å oppdatere Radarr",
"UsingExternalUpdateMechanismBranchUsedByExternalUpdateMechanism": "Gren brukt av ekstern oppdateringsmekanisme",
"BranchUpdate": "Gren som skal brukes til å oppdatere Radarr",
"BranchUpdateMechanism": "Gren brukt av ekstern oppdateringsmekanisme",
"DeleteDownloadClientMessageText": "Er du sikker på at du vil slette formattaggen {0}?",
"DeleteImportListMessageText": "Er du sikker på at du vil slette formattaggen {0}?",
"DeleteIndexerMessageText": "Er du sikker på at du vil slette formattaggen {0}?",

View File

@@ -43,7 +43,7 @@
"Calendar": "Kalender",
"CalendarWeekColumnHeaderHelpText": "Wordt getoond boven elke kolom wanneer de actieve weergave Week is",
"Cancel": "Annuleer",
"CancelMessageText": "Bent u zeker dat u deze taak in afwachting wilt annuleren?",
"CancelPendingTask": "Bent u zeker dat u deze taak in afwachting wilt annuleren?",
"CertificateValidation": "Certificaat Validatie",
"CertificateValidationHelpText": "Wijzig hoe strict HTTPS certificaat validatie is. Wijzig dit niet behalve als je de risico's begrijpt.",
"ChangeFileDate": "Wijzig Bestandsdatum",
@@ -424,8 +424,8 @@
"UsenetDelay": "Usenet Vertraging",
"UsenetDelayHelpText": "Vertraging in minuten om te wachten voordat een uitgave wordt opgehaald van Usenet",
"Username": "Gebruikersnaam",
"UsingExternalUpdateMechanismBranchToUseToUpdateReadarr": "Te gebruiken branch om Radarr bij te werken",
"UsingExternalUpdateMechanismBranchUsedByExternalUpdateMechanism": "Gebruikte branch door extern update mechanisme",
"BranchUpdate": "Te gebruiken branch om Radarr bij te werken",
"BranchUpdateMechanism": "Gebruikte branch door extern update mechanisme",
"Version": "Versie",
"WeekColumnHeader": "Week Kolom Koptekst",
"Year": "Jaar",

View File

@@ -80,7 +80,7 @@
"Calendar": "Kalendarz",
"CalendarWeekColumnHeaderHelpText": "Wyświetlany nad każdą kolumną, gdy tydzień jest aktywnym widokiem",
"Cancel": "Anuluj",
"CancelMessageText": "Czy na pewno chcesz anulować to oczekujące zadanie?",
"CancelPendingTask": "Czy na pewno chcesz anulować to oczekujące zadanie?",
"CertificateValidation": "Walidacja certyfikatu",
"CertificateValidationHelpText": "Zmień ścisłość walidacji certyfikatu HTTPS. Nie zmieniaj, jeśli nie rozumiesz związanych z tym zagrożeń.",
"ChangeFileDate": "Zmień datę pliku",
@@ -429,8 +429,8 @@
"UsenetDelay": "Opóźnienie Usenetu",
"UsenetDelayHelpText": "Opóźnij w ciągu kilku minut, aby poczekać przed pobraniem wersji z Usenetu",
"Username": "Nazwa Użytkownika",
"UsingExternalUpdateMechanismBranchToUseToUpdateReadarr": "Oddział do użycia do aktualizacji Radarr",
"UsingExternalUpdateMechanismBranchUsedByExternalUpdateMechanism": "Gałąź używana przez zewnętrzny mechanizm aktualizacji",
"BranchUpdate": "Oddział do użycia do aktualizacji Radarr",
"BranchUpdateMechanism": "Gałąź używana przez zewnętrzny mechanizm aktualizacji",
"Version": "Wersja",
"WeekColumnHeader": "Nagłówek kolumny tygodnia",
"YesCancel": "Tak, anuluj",

View File

@@ -50,8 +50,8 @@
"UsenetDelay": "Atraso para Usenet",
"UsenetDelayHelpText": "Tempo, em minutos, para aguardar antes de capturar uma versão de Usenet",
"Username": "Nome de utilizador",
"UsingExternalUpdateMechanismBranchToUseToUpdateReadarr": "Ramificação utilizada para atualizar o Readarr",
"UsingExternalUpdateMechanismBranchUsedByExternalUpdateMechanism": "Ramificação utilizada pelo mecanismo externo de atualização",
"BranchUpdate": "Ramificação utilizada para atualizar o Readarr",
"BranchUpdateMechanism": "Ramificação utilizada pelo mecanismo externo de atualização",
"Version": "Versão",
"WeekColumnHeader": "Cabeçalho da coluna de semana",
"Year": "Ano",
@@ -165,7 +165,7 @@
"Calendar": "Calendário",
"CalendarWeekColumnHeaderHelpText": "Mostrar acima de cada coluna quando a semana é a vista ativa",
"Cancel": "Cancelar",
"CancelMessageText": "Tem a certeza que quer cancelar esta tarefa pendente?",
"CancelPendingTask": "Tem a certeza que quer cancelar esta tarefa pendente?",
"CertificateValidation": "Validação de certificado",
"CertificateValidationHelpText": "Mudar nível de restrição da validação da certificação HTTPS",
"ChangeFileDate": "Modificar data do ficheiro",

View File

@@ -73,7 +73,7 @@
"Calendar": "Calendário",
"CalendarWeekColumnHeaderHelpText": "Mostrar acima de cada coluna quando a semana está na exibição ativa",
"Cancel": "Cancelar",
"CancelMessageText": "Tem certeza que deseja cancelar esta tarefa pendente?",
"CancelPendingTask": "Tem certeza que deseja cancelar esta tarefa pendente?",
"CertificateValidation": "Validação de certificado",
"CertificateValidationHelpText": "Altere a rigidez da validação da certificação HTTPS. Não mude a menos que você entenda os riscos.",
"ChangeFileDate": "Alterar data do arquivo",
@@ -427,8 +427,8 @@
"UsenetDelay": "Atraso da Usenet",
"UsenetDelayHelpText": "Atraso em minutos para esperar antes de pegar um lançamento da Usenet",
"Username": "Nome do usuário",
"UsingExternalUpdateMechanismBranchToUseToUpdateReadarr": "Ramificação para atualizar o Readarr",
"UsingExternalUpdateMechanismBranchUsedByExternalUpdateMechanism": "Ramificação usada pelo mecanismo de atualização externo",
"BranchUpdate": "Ramificação para atualizar o Readarr",
"BranchUpdateMechanism": "Ramificação usada pelo mecanismo de atualização externo",
"Version": "Versão",
"WeekColumnHeader": "Cabeçalho da Coluna da Semana",
"Year": "Ano",

View File

@@ -110,7 +110,7 @@
"Calendar": "Calendar",
"CalendarWeekColumnHeaderHelpText": "Afișat deasupra fiecărei coloane când săptămâna este vizualizarea activă",
"Cancel": "Anulează",
"CancelMessageText": "Sigur doriți să anulați această sarcină în așteptare?",
"CancelPendingTask": "Sigur doriți să anulați această sarcină în așteptare?",
"CertificateValidation": "Validarea certificatului",
"CertificateValidationHelpText": "Modificați cât de strictă este validarea certificării HTTPS. Nu schimbați dacă nu înțelegeți riscurile.",
"ChangeHasNotBeenSavedYet": "Modificarea nu a fost încă salvată",
@@ -428,8 +428,8 @@
"UsenetDelay": "Întârziere Usenet",
"UsenetDelayHelpText": "Întârziați în câteva minute pentru a aștepta înainte de a lua o eliberare de la Usenet",
"Username": "Nume utilizator",
"UsingExternalUpdateMechanismBranchToUseToUpdateReadarr": "Sucursală de utilizat pentru actualizarea Radarr",
"UsingExternalUpdateMechanismBranchUsedByExternalUpdateMechanism": "Ramură utilizată de mecanismul extern de actualizare",
"BranchUpdate": "Sucursală de utilizat pentru actualizarea Radarr",
"BranchUpdateMechanism": "Ramură utilizată de mecanismul extern de actualizare",
"Version": "Versiune",
"WeekColumnHeader": "Antetul coloanei săptămânii",
"Year": "An",

View File

@@ -45,7 +45,7 @@
"Calendar": "Календарь",
"CalendarWeekColumnHeaderHelpText": "Отображается над каждым столбцом, когда неделя активна",
"Cancel": "Отменить",
"CancelMessageText": "Вы уверены, что хотите убрать данную задачу из очереди?",
"CancelPendingTask": "Вы уверены, что хотите убрать данную задачу из очереди?",
"CertificateValidation": "Проверка сертификата",
"CertificateValidationHelpText": "Измените строгую проверку сертификации HTTPS. Не меняйте, если вы не понимаете риски.",
"ChangeFileDate": "Изменить дату файла",
@@ -429,8 +429,8 @@
"UsenetDelay": "Usenet задержки",
"UsenetDelayHelpText": "Задержка в минутах перед получением релиза из Usenet",
"Username": "Пользователь",
"UsingExternalUpdateMechanismBranchToUseToUpdateReadarr": "Ветвь для обновления Radarr",
"UsingExternalUpdateMechanismBranchUsedByExternalUpdateMechanism": "Ветвь, используемая внешним механизмом обновления",
"BranchUpdate": "Ветвь для обновления Radarr",
"BranchUpdateMechanism": "Ветвь, используемая внешним механизмом обновления",
"Version": "Версия",
"WeekColumnHeader": "Заголовок столбца недели",
"Year": "Год",

View File

@@ -20,8 +20,8 @@
"DeleteTagMessageText": "Naozaj chcete zmazať značku formátu {0} ?",
"ResetAPIKeyMessageText": "Naozaj chcete obnoviť kľúč API?",
"ShowQualityProfile": "Pridajte profil kvality",
"UsingExternalUpdateMechanismBranchToUseToUpdateReadarr": "Vetva, ktorá sa má použiť k aktualizácií Radarru",
"UsingExternalUpdateMechanismBranchUsedByExternalUpdateMechanism": "Vetva používaná externým mechanizmom aktualizácie",
"BranchUpdate": "Vetva, ktorá sa má použiť k aktualizácií Radarru",
"BranchUpdateMechanism": "Vetva používaná externým mechanizmom aktualizácie",
"AutoRedownloadFailedHelpText": "Automaticky vyhľadať a pokúsiť sa stiahnuť iné vydanie",
"AutoUnmonitorPreviouslyDownloadedBooksHelpText": "Filmy odstránené z disku sa automaticky prestanú v Radarre sledovať",
"BackupFolderHelpText": "Relatívne cesty budú v priečinku AppData Radarru",
@@ -114,7 +114,7 @@
"IsCutoffCutoff": "Hranica",
"Label": "Štítok",
"Remove": "Odstrániť",
"CancelMessageText": "Naozaj chcete zrušiť túto prebiehajúcu úlohu?",
"CancelPendingTask": "Naozaj chcete zrušiť túto prebiehajúcu úlohu?",
"Publisher": "Vydavateľ",
"Quality": "kvalita",
"QualityProfile": "Profil kvality",

View File

@@ -50,7 +50,7 @@
"Calendar": "Kalender",
"CalendarWeekColumnHeaderHelpText": "Visas ovanför varje kolumn när veckan är den aktiva vyn",
"Cancel": "Avbryt",
"CancelMessageText": "Är du säker på att du vill avbryta den väntande uppgiften?",
"CancelPendingTask": "Är du säker på att du vill avbryta den väntande uppgiften?",
"CertificateValidation": "Validering av Certifikat",
"CertificateValidationHelpText": "Ändra hur strikt valideringen av HTTPS certifikat är",
"ChangeFileDate": "Ändra fildatum",
@@ -429,8 +429,8 @@
"Usenet": "Usenet",
"UsenetDelay": "Usenet fördröjning",
"UsenetDelayHelpText": "Fördröja på några minuter för att vänta innan du hämtar en utgåva från Usenet",
"UsingExternalUpdateMechanismBranchToUseToUpdateReadarr": "Gren att använda för att uppdatera Radarr",
"UsingExternalUpdateMechanismBranchUsedByExternalUpdateMechanism": "Gren som används av extern uppdateringsmekanism",
"BranchUpdate": "Gren att använda för att uppdatera Radarr",
"BranchUpdateMechanism": "Gren som används av extern uppdateringsmekanism",
"Version": "Version",
"WeekColumnHeader": "Rubrik för veckokolumn",
"Year": "År",

View File

@@ -47,7 +47,7 @@
"Calendar": "ปฏิทิน",
"CalendarWeekColumnHeaderHelpText": "แสดงอยู่เหนือแต่ละคอลัมน์เมื่อสัปดาห์เป็นมุมมองที่ใช้งานอยู่",
"Cancel": "ยกเลิก",
"CancelMessageText": "แน่ใจไหมว่าต้องการยกเลิกงานที่รอดำเนินการนี้",
"CancelPendingTask": "แน่ใจไหมว่าต้องการยกเลิกงานที่รอดำเนินการนี้",
"CertificateValidation": "การตรวจสอบใบรับรอง",
"CertificateValidationHelpText": "เปลี่ยนวิธีการตรวจสอบการรับรอง HTTPS ที่เข้มงวด",
"ChangeFileDate": "เปลี่ยนวันที่ของไฟล์",
@@ -429,8 +429,8 @@
"UsenetDelay": "Usenet ล่าช้า",
"UsenetDelayHelpText": "รอเป็นนาทีก่อนที่จะคว้ารุ่นจาก Usenet",
"Username": "ชื่อผู้ใช้",
"UsingExternalUpdateMechanismBranchToUseToUpdateReadarr": "สาขาที่จะใช้ในการอัปเดต Radarr",
"UsingExternalUpdateMechanismBranchUsedByExternalUpdateMechanism": "สาขาที่ใช้โดยกลไกการอัพเดตภายนอก",
"BranchUpdate": "สาขาที่จะใช้ในการอัปเดต Radarr",
"BranchUpdateMechanism": "สาขาที่ใช้โดยกลไกการอัพเดตภายนอก",
"Version": "เวอร์ชัน",
"WeekColumnHeader": "ส่วนหัวคอลัมน์สัปดาห์",
"Year": "ปี",

View File

@@ -45,7 +45,7 @@
"Calendar": "Takvim",
"CalendarWeekColumnHeaderHelpText": "Aktif görünüm hafta olduğunda her bir sütunun üzerinde gösterilir",
"Cancel": "Vazgeç",
"CancelMessageText": "Bu bekleyen görevi iptal etmek istediğinizden emin misiniz?",
"CancelPendingTask": "Bu bekleyen görevi iptal etmek istediğinizden emin misiniz?",
"CertificateValidation": "Sertifika Doğrulama",
"CertificateValidationHelpText": "HTTPS sertifika doğrulamasının sıkılığını değiştirin. Riskleri anlamadığınız sürece değişmeyin.",
"ChangeFileDate": "Dosya Tarihini Değiştir",
@@ -429,8 +429,8 @@
"UsenetDelay": "Usenet Gecikmesi",
"UsenetDelayHelpText": "Usenet'ten bir yayın almadan önce beklemek için dakika cinsinden gecikme",
"Username": "Kullanıcı adı",
"UsingExternalUpdateMechanismBranchToUseToUpdateReadarr": "Radarr'ı güncellemek için kullanılacak dal",
"UsingExternalUpdateMechanismBranchUsedByExternalUpdateMechanism": "Harici güncelleme mekanizması tarafından kullanılan dal",
"BranchUpdate": "Radarr'ı güncellemek için kullanılacak dal",
"BranchUpdateMechanism": "Harici güncelleme mekanizması tarafından kullanılan dal",
"Version": "Sürüm",
"WeekColumnHeader": "Hafta Sütun Başlığı",
"Year": "Yıl",

View File

@@ -56,7 +56,7 @@
"BindAddressHelpText": "Дійсна адреса IPv4 або '*' для всіх інтерфейсів",
"Blocklist": "Чорний список",
"BlocklistRelease": "Реліз із чорного списку",
"CancelMessageText": "Ви впевнені, що хочете скасувати це незавершене завдання?",
"CancelPendingTask": "Ви впевнені, що хочете скасувати це незавершене завдання?",
"ChownGroupHelpText": "Назва групи або gid. Використовуйте gid для віддалених файлових систем.",
"ChownGroupHelpTextWarning": "Це працює лише в тому випадку, якщо власником файлу є користувач, на якому працює Radarr. Краще переконатися, що клієнт для завантаження використовує ту саму групу, що й Radarr.",
"DeleteReleaseProfile": "Видалити профіль випуску",
@@ -74,7 +74,7 @@
"DeleteQualityProfileMessageText": "Ви впевнені, що хочете видалити профіль якості '{name}'?",
"DeleteRootFolderMessageText": "Ви впевнені, що хочете видалити тег {0} ?",
"DeleteTagMessageText": "Ви впевнені, що хочете видалити тег {0} ?",
"UsingExternalUpdateMechanismBranchToUseToUpdateReadarr": "Гілка для оновлення Radarr",
"BranchUpdate": "Гілка для оновлення Radarr",
"ChmodFolderHelpTextWarning": "Це працює лише в тому випадку, якщо власником файлу є користувач, на якому працює Radarr. Краще переконатися, що клієнт завантаження правильно встановлює дозволи.",
"ResetAPIKeyMessageText": "Ви впевнені, що хочете скинути свій ключ API?",
"CouldntFindAnyResultsForTerm": "Не вдалося знайти жодних результатів для '{0}'",
@@ -87,7 +87,7 @@
"AuthorClickToChangeBook": "Натисніть, щоб змінити фільм",
"AutoUnmonitorPreviouslyDownloadedBooksHelpText": "Фільми, видалені з диска, автоматично не відстежуються в Radarr",
"BackupFolderHelpText": "Відносні шляхи будуть у каталозі AppData Radarr",
"UsingExternalUpdateMechanismBranchUsedByExternalUpdateMechanism": "Гілка, що використовується зовнішнім механізмом оновлення",
"BranchUpdateMechanism": "Гілка, що використовується зовнішнім механізмом оновлення",
"AddList": "Додати список",
"ShowDateAdded": "Показати дату додавання",
"UnableToLoadBlocklist": "Не вдалося завантажити список блокувань",

View File

@@ -52,7 +52,7 @@
"Calendar": "Lịch",
"CalendarWeekColumnHeaderHelpText": "Được hiển thị phía trên mỗi cột khi tuần là chế độ xem đang hoạt động",
"Cancel": "Huỷ bỏ",
"CancelMessageText": "Bạn có chắc chắn muốn hủy nhiệm vụ đang chờ xử lý này không?",
"CancelPendingTask": "Bạn có chắc chắn muốn hủy nhiệm vụ đang chờ xử lý này không?",
"CertificateValidation": "Xác thực chứng chỉ",
"CertificateValidationHelpText": "Thay đổi cách xác thực chứng chỉ HTTPS nghiêm ngặt. Không được đổi nếu bạn biết rõ về",
"ChangeFileDate": "Thay đổi ngày tệp",
@@ -422,8 +422,8 @@
"UsenetDelay": "Sự chậm trễ của Usenet",
"UsenetDelayHelpText": "Trì hoãn vài phút để đợi trước khi lấy bản phát hành từ Usenet",
"Username": "tên tài khoản",
"UsingExternalUpdateMechanismBranchToUseToUpdateReadarr": "Nhánh sử dụng để cập nhật Radarr",
"UsingExternalUpdateMechanismBranchUsedByExternalUpdateMechanism": "Nhánh được sử dụng bởi cơ chế cập nhật bên ngoài",
"BranchUpdate": "Nhánh sử dụng để cập nhật Radarr",
"BranchUpdateMechanism": "Nhánh được sử dụng bởi cơ chế cập nhật bên ngoài",
"Version": "Phiên bản",
"WeekColumnHeader": "Tiêu đề cột tuần",
"Year": "Năm",

View File

@@ -33,7 +33,7 @@
"Calendar": "日历",
"CalendarWeekColumnHeaderHelpText": "当使用周视图时显示上面的每一列",
"Cancel": "取消",
"CancelMessageText": "您确定要取消这个挂起的任务吗?",
"CancelPendingTask": "您确定要取消这个挂起的任务吗?",
"CertificateValidation": "验证证书",
"CertificateValidationHelpText": "改变HTTPS证书验证的严格程度。不要更改除非您了解风险。",
"ChangeFileDate": "修改文件日期",
@@ -415,8 +415,8 @@
"UsenetDelay": "Usenet延时",
"UsenetDelayHelpText": "延迟几分钟才能等待从Usenet获取发布",
"Username": "用户名",
"UsingExternalUpdateMechanismBranchToUseToUpdateReadarr": "更新Radarr的分支",
"UsingExternalUpdateMechanismBranchUsedByExternalUpdateMechanism": "外部更新机制使用的分支",
"BranchUpdate": "更新Radarr的分支",
"BranchUpdateMechanism": "外部更新机制使用的分支",
"Version": "版本",
"WeekColumnHeader": "日期格式",
"Year": "年",

View File

@@ -136,7 +136,7 @@
"RootFolder": "根目錄資料夾",
"Settings": "設定",
"SomeResultsAreHiddenByTheAppliedFilter": "根據所使用的篩選器已將所有結果隱藏",
"UsingExternalUpdateMechanismBranchUsedByExternalUpdateMechanism": "外部更新機制使用的分支",
"BranchUpdateMechanism": "外部更新機制使用的分支",
"DeleteImportListExclusion": "新增排除清單",
"ApplyTagsHelpTextHowToApplyIndexers": "如何套用標籤在所選擇的輸入清單",
"UnableToAddANewImportListExclusionPleaseTryAgain": "無法加入新的條件,請重新嘗試。",

View File

@@ -25,15 +25,15 @@ namespace NzbDrone.Core.Notifications.Discord
public override void OnGrab(GrabMessage message)
{
var embeds = new List<Embed>
{
new Embed
{
Description = message.Message,
Title = message.Author.Name,
Text = message.Message,
Color = (int)DiscordColors.Warning
}
};
{
new ()
{
Description = message.Message,
Title = message.Author.Name,
Text = message.Message,
Color = (int)DiscordColors.Warning
}
};
var payload = CreatePayload($"Grabbed: {message.Message}", embeds);
_proxy.SendPayload(payload, Settings);
@@ -43,7 +43,7 @@ namespace NzbDrone.Core.Notifications.Discord
{
var attachments = new List<Embed>
{
new Embed
new ()
{
Description = message.Message,
Title = message.Author.Name,
@@ -59,12 +59,12 @@ namespace NzbDrone.Core.Notifications.Discord
public override void OnRename(Author author, List<RenamedBookFile> renamedFiles)
{
var attachments = new List<Embed>
{
new Embed
{
Title = author.Name,
}
};
{
new ()
{
Title = author.Name,
}
};
var payload = CreatePayload("Renamed", attachments);
@@ -74,21 +74,21 @@ namespace NzbDrone.Core.Notifications.Discord
public override void OnAuthorAdded(Author author)
{
var attachments = new List<Embed>
{
new Embed
{
Title = author.Name,
Fields = new List<DiscordField>()
{
new DiscordField()
{
Name = "Links",
Value = string.Join(" / ", author.Metadata.Value.Links.Select(link => $"[{link.Name}]({link.Url})"))
}
},
}
};
var payload = CreatePayload($"Author Added", attachments);
{
new ()
{
Title = author.Name,
Fields = new List<DiscordField>()
{
new ()
{
Name = "Links",
Value = string.Join(" / ", author.Metadata.Value.Links.Select(link => $"[{link.Name}]({link.Url})"))
}
},
}
};
var payload = CreatePayload("Author Added", attachments);
_proxy.SendPayload(payload, Settings);
}
@@ -96,13 +96,13 @@ namespace NzbDrone.Core.Notifications.Discord
public override void OnAuthorDelete(AuthorDeleteMessage deleteMessage)
{
var attachments = new List<Embed>
{
new Embed
{
Title = deleteMessage.Author.Name,
Description = deleteMessage.DeletedFilesMessage
}
};
{
new ()
{
Title = deleteMessage.Author.Name,
Description = deleteMessage.DeletedFilesMessage
}
};
var payload = CreatePayload("Author Deleted", attachments);
@@ -112,13 +112,13 @@ namespace NzbDrone.Core.Notifications.Discord
public override void OnBookDelete(BookDeleteMessage deleteMessage)
{
var attachments = new List<Embed>
{
new Embed
{
Title = $"${deleteMessage.Book.Author.Value.Name} - ${deleteMessage.Book.Title}",
Description = deleteMessage.DeletedFilesMessage
}
};
{
new ()
{
Title = $"{deleteMessage.Book.Author.Value.Name} - ${deleteMessage.Book.Title}",
Description = deleteMessage.DeletedFilesMessage
}
};
var payload = CreatePayload("Book Deleted", attachments);
@@ -128,13 +128,13 @@ namespace NzbDrone.Core.Notifications.Discord
public override void OnBookFileDelete(BookFileDeleteMessage deleteMessage)
{
var attachments = new List<Embed>
{
new Embed
{
Title = $"${deleteMessage.Book.Author.Value.Name} - ${deleteMessage.Book.Title} - file deleted",
Description = deleteMessage.BookFile.Path
}
};
{
new ()
{
Title = $"{deleteMessage.Book.Author.Value.Name} - ${deleteMessage.Book.Title} - file deleted",
Description = deleteMessage.BookFile.Path
}
};
var payload = CreatePayload("Book File Deleted", attachments);
@@ -144,14 +144,14 @@ namespace NzbDrone.Core.Notifications.Discord
public override void OnHealthIssue(HealthCheck.HealthCheck healthCheck)
{
var attachments = new List<Embed>
{
new Embed
{
Title = healthCheck.Source.Name,
Text = healthCheck.Message,
Color = healthCheck.Type == HealthCheck.HealthCheckResult.Warning ? (int)DiscordColors.Warning : (int)DiscordColors.Danger
}
};
{
new ()
{
Title = healthCheck.Source.Name,
Text = healthCheck.Message,
Color = healthCheck.Type == HealthCheck.HealthCheckResult.Warning ? (int)DiscordColors.Warning : (int)DiscordColors.Danger
}
};
var payload = CreatePayload("Health Issue", attachments);
@@ -161,13 +161,13 @@ namespace NzbDrone.Core.Notifications.Discord
public override void OnBookRetag(BookRetagMessage message)
{
var attachments = new List<Embed>
{
new Embed
{
Title = BOOK_RETAGGED_TITLE,
Text = message.Message
}
};
{
new ()
{
Title = BOOK_RETAGGED_TITLE,
Text = message.Message
}
};
var payload = CreatePayload($"Track file tags updated: {message.Message}", attachments);
@@ -178,7 +178,7 @@ namespace NzbDrone.Core.Notifications.Discord
{
var attachments = new List<Embed>
{
new Embed
new ()
{
Description = message.Message,
Title = message.SourceTitle,
@@ -195,7 +195,7 @@ namespace NzbDrone.Core.Notifications.Discord
{
var attachments = new List<Embed>
{
new Embed
new ()
{
Description = message.Message,
Title = message.Book?.Title ?? message.Message,
@@ -211,32 +211,32 @@ namespace NzbDrone.Core.Notifications.Discord
public override void OnApplicationUpdate(ApplicationUpdateMessage updateMessage)
{
var attachments = new List<Embed>
{
new Embed
{
Author = new DiscordAuthor
{
Name = Settings.Author.IsNullOrWhiteSpace() ? Environment.MachineName : Settings.Author,
IconUrl = "https://raw.githubusercontent.com/Readarr/Readarr/develop/Logo/256.png"
},
Title = APPLICATION_UPDATE_TITLE,
Timestamp = DateTime.UtcNow.ToString("yyyy-MM-ddTHH:mm:ss.fffZ"),
Color = (int)DiscordColors.Standard,
Fields = new List<DiscordField>()
{
new DiscordField()
{
Name = "Previous Version",
Value = updateMessage.PreviousVersion.ToString()
},
new DiscordField()
{
Name = "New Version",
Value = updateMessage.NewVersion.ToString()
}
},
}
};
{
new ()
{
Author = new DiscordAuthor
{
Name = Settings.Author.IsNullOrWhiteSpace() ? Environment.MachineName : Settings.Author,
IconUrl = "https://raw.githubusercontent.com/Readarr/Readarr/develop/Logo/256.png"
},
Title = APPLICATION_UPDATE_TITLE,
Timestamp = DateTime.UtcNow.ToString("yyyy-MM-ddTHH:mm:ss.fffZ"),
Color = (int)DiscordColors.Standard,
Fields = new List<DiscordField>()
{
new ()
{
Name = "Previous Version",
Value = updateMessage.PreviousVersion.ToString()
},
new ()
{
Name = "New Version",
Value = updateMessage.NewVersion.ToString()
}
},
}
};
var payload = CreatePayload(null, attachments);

View File

@@ -4,6 +4,7 @@
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Dapper" />
<PackageReference Include="Diacritical.Net" />
<PackageReference Include="LazyCache" />
<PackageReference Include="Polly" />
<PackageReference Include="System.Text.Json" />

View File

@@ -7,5 +7,7 @@ namespace NzbDrone.Core.Update.Commands
public override bool SendUpdatesToClient => true;
public override string CompletionMessage => null;
public bool InstallMajorUpdate { get; set; }
}
}

View File

@@ -4,6 +4,7 @@ namespace NzbDrone.Core.Update.Commands
{
public class ApplicationUpdateCommand : Command
{
public bool InstallMajorUpdate { get; set; }
public override bool SendUpdatesToClient => true;
public override bool IsExclusive => true;
}

View File

@@ -20,7 +20,7 @@ using NzbDrone.Core.Update.Commands;
namespace NzbDrone.Core.Update
{
public class InstallUpdateService : IExecute<ApplicationUpdateCheckCommand>, IExecute<ApplicationUpdateCommand>, IHandle<ApplicationStartingEvent>
public class InstallUpdateService : IExecute<ApplicationUpdateCommand>, IExecute<ApplicationUpdateCheckCommand>, IHandle<ApplicationStartingEvent>
{
private readonly ICheckUpdateService _checkUpdateService;
private readonly Logger _logger;
@@ -83,7 +83,7 @@ namespace NzbDrone.Core.Update
{
EnsureAppDataSafety();
if (OsInfo.IsWindows || _configFileProvider.UpdateMechanism != UpdateMechanism.Script)
if (_configFileProvider.UpdateMechanism != UpdateMechanism.Script)
{
var startupFolder = _appFolderInfo.StartUpFolder;
var uiFolder = Path.Combine(startupFolder, "UI");
@@ -143,7 +143,7 @@ namespace NzbDrone.Core.Update
_backupService.Backup(BackupType.Update);
if (OsInfo.IsNotWindows && _configFileProvider.UpdateMechanism == UpdateMechanism.Script)
if (_configFileProvider.UpdateMechanism == UpdateMechanism.Script)
{
InstallUpdateWithScript(updateSandboxFolder);
return true;
@@ -232,7 +232,7 @@ namespace NzbDrone.Core.Update
}
}
private UpdatePackage GetUpdatePackage(CommandTrigger updateTrigger)
private UpdatePackage GetUpdatePackage(CommandTrigger updateTrigger, bool installMajorUpdate)
{
_logger.ProgressDebug("Checking for updates");
@@ -244,7 +244,13 @@ namespace NzbDrone.Core.Update
return null;
}
if (OsInfo.IsNotWindows && !_configFileProvider.UpdateAutomatically && updateTrigger != CommandTrigger.Manual)
if (latestAvailable.Version.Major > BuildInfo.Version.Major && !installMajorUpdate)
{
_logger.ProgressInfo("Unable to install major update, please update update manually from System: Updates");
return null;
}
if (!_configFileProvider.UpdateAutomatically && updateTrigger != CommandTrigger.Manual)
{
_logger.ProgressDebug("Auto-update not enabled, not installing available update.");
return null;
@@ -273,7 +279,7 @@ namespace NzbDrone.Core.Update
public void Execute(ApplicationUpdateCheckCommand message)
{
if (GetUpdatePackage(message.Trigger) != null)
if (GetUpdatePackage(message.Trigger, true) != null)
{
_commandQueueManager.Push(new ApplicationUpdateCommand(), trigger: message.Trigger);
}
@@ -281,7 +287,7 @@ namespace NzbDrone.Core.Update
public void Execute(ApplicationUpdateCommand message)
{
var latestAvailable = GetUpdatePackage(message.Trigger);
var latestAvailable = GetUpdatePackage(message.Trigger, message.InstallMajorUpdate);
if (latestAvailable != null)
{

View File

@@ -1,4 +1,4 @@
using NzbDrone.Common.EnvironmentInfo;
using NzbDrone.Common.EnvironmentInfo;
using NzbDrone.Core.Configuration;
namespace NzbDrone.Core.Update

View File

@@ -42,6 +42,7 @@ namespace NzbDrone.Core.Update
.AddQueryParam("runtime", "netcore")
.AddQueryParam("runtimeVer", _platformInfo.Version)
.AddQueryParam("dbType", _mainDatabase.DatabaseType)
.AddQueryParam("includeMajorVersion", true)
.SetSegment("branch", branch);
if (_analyticsService.IsEnabled)

View File

@@ -135,7 +135,7 @@ namespace NzbDrone.Host
Name = "apikey",
Type = SecuritySchemeType.ApiKey,
Scheme = "apiKey",
Description = "Apikey passed as header",
Description = "Apikey passed as query parameter",
In = ParameterLocation.Query,
Reference = new OpenApiReference
{

View File

@@ -7,7 +7,7 @@ using Readarr.Api.V1.Author;
namespace NzbDrone.Integration.Test.ApiTests
{
[TestFixture]
[Ignore("Waiting for metadata to be back again", Until = "2024-08-15 00:00:00Z")]
[Ignore("Waiting for metadata to be back again", Until = "2024-12-15 00:00:00Z")]
public class AuthorEditorFixture : IntegrationTest
{
private void GivenExistingAuthor()

View File

@@ -7,7 +7,7 @@ using NUnit.Framework;
namespace NzbDrone.Integration.Test.ApiTests
{
[TestFixture]
[Ignore("Waiting for metadata to be back again", Until = "2024-08-15 00:00:00Z")]
[Ignore("Waiting for metadata to be back again", Until = "2024-12-15 00:00:00Z")]
public class AuthorFixture : IntegrationTest
{
[Test]

View File

@@ -4,7 +4,7 @@ using NUnit.Framework;
namespace NzbDrone.Integration.Test.ApiTests
{
[TestFixture]
[Ignore("Waiting for metadata to be back again", Until = "2024-08-15 00:00:00Z")]
[Ignore("Waiting for metadata to be back again", Until = "2024-12-15 00:00:00Z")]
public class AuthorLookupFixture : IntegrationTest
{
[TestCase("Robert Harris", "Robert Harris")]

View File

@@ -6,7 +6,7 @@ using Readarr.Api.V1.Blocklist;
namespace NzbDrone.Integration.Test.ApiTests
{
[TestFixture]
[Ignore("Waiting for metadata to be back again", Until = "2024-08-15 00:00:00Z")]
[Ignore("Waiting for metadata to be back again", Until = "2024-12-15 00:00:00Z")]
public class BlocklistFixture : IntegrationTest
{
private AuthorResource _author;

View File

@@ -9,7 +9,7 @@ using Readarr.Api.V1.Books;
namespace NzbDrone.Integration.Test.ApiTests
{
[TestFixture]
[Ignore("Waiting for metadata to be back again", Until = "2024-08-15 00:00:00Z")]
[Ignore("Waiting for metadata to be back again", Until = "2024-12-15 00:00:00Z")]
public class CalendarFixture : IntegrationTest
{
public ClientBase<BookResource> Calendar;

View File

@@ -8,7 +8,7 @@ using Readarr.Api.V1.RootFolders;
namespace NzbDrone.Integration.Test.ApiTests.WantedTests
{
[TestFixture]
[Ignore("Waiting for metadata to be back again", Until = "2024-08-15 00:00:00Z")]
[Ignore("Waiting for metadata to be back again", Until = "2024-12-15 00:00:00Z")]
public class CutoffUnmetFixture : IntegrationTest
{
[SetUp]

View File

@@ -7,7 +7,7 @@ using Readarr.Api.V1.RootFolders;
namespace NzbDrone.Integration.Test.ApiTests.WantedTests
{
[TestFixture]
[Ignore("Waiting for metadata to be back again", Until = "2024-08-15 00:00:00Z")]
[Ignore("Waiting for metadata to be back again", Until = "2024-12-15 00:00:00Z")]
public class MissingFixture : IntegrationTest
{
[SetUp]

View File

@@ -13815,7 +13815,7 @@
},
"apikey": {
"type": "apiKey",
"description": "Apikey passed as header",
"description": "Apikey passed as query parameter",
"name": "apikey",
"in": "query"
}

View File

@@ -1,12 +1,18 @@
using System;
using System.Text.RegularExpressions;
using Diacritical;
using Microsoft.AspNetCore.Authentication;
using Microsoft.AspNetCore.Authentication.Cookies;
using Microsoft.Extensions.DependencyInjection;
using NzbDrone.Core.Authentication;
using NzbDrone.Core.Configuration;
namespace Readarr.Http.Authentication
{
public static class AuthenticationBuilderExtensions
{
private static readonly Regex CookieNameRegex = new Regex(@"[^a-z0-9]+", RegexOptions.Compiled | RegexOptions.IgnoreCase);
public static AuthenticationBuilder AddApiKey(this AuthenticationBuilder authenticationBuilder, string name, Action<ApiKeyAuthenticationOptions> options)
{
return authenticationBuilder.AddScheme<ApiKeyAuthenticationOptions, ApiKeyAuthenticationHandler>(name, options);
@@ -29,19 +35,27 @@ namespace Readarr.Http.Authentication
public static AuthenticationBuilder AddAppAuthentication(this IServiceCollection services)
{
return services.AddAuthentication()
.AddNone(AuthenticationType.None.ToString())
.AddExternal(AuthenticationType.External.ToString())
.AddBasic(AuthenticationType.Basic.ToString())
.AddCookie(AuthenticationType.Forms.ToString(), options =>
services.AddOptions<CookieAuthenticationOptions>(AuthenticationType.Forms.ToString())
.Configure<IConfigFileProvider>((options, configFileProvider) =>
{
options.Cookie.Name = "ReadarrAuth";
// Replace diacritics and replace non-word characters to ensure cookie name doesn't contain any valid URL characters not allowed in cookie names
var instanceName = configFileProvider.InstanceName;
instanceName = instanceName.RemoveDiacritics();
instanceName = CookieNameRegex.Replace(instanceName, string.Empty);
options.Cookie.Name = $"{instanceName}Auth";
options.AccessDeniedPath = "/login?loginFailed=true";
options.LoginPath = "/login";
options.ExpireTimeSpan = TimeSpan.FromDays(7);
options.SlidingExpiration = true;
options.ReturnUrlParameter = "returnUrl";
})
});
return services.AddAuthentication()
.AddNone(AuthenticationType.None.ToString())
.AddExternal(AuthenticationType.External.ToString())
.AddBasic(AuthenticationType.Basic.ToString())
.AddCookie(AuthenticationType.Forms.ToString())
.AddApiKey("API", options =>
{
options.HeaderName = "X-Api-Key";

View File

@@ -47,7 +47,7 @@ namespace Readarr.Http.Authentication
await HttpContext.SignInAsync(AuthenticationType.Forms.ToString(), new ClaimsPrincipal(new ClaimsIdentity(claims, "Cookies", "user", "identifier")), authProperties);
if (returnUrl.IsNullOrWhiteSpace())
if (returnUrl.IsNullOrWhiteSpace() || !Url.IsLocalUrl(returnUrl))
{
return Redirect(_configFileProvider.UrlBase + "/");
}

View File

@@ -20,6 +20,8 @@ namespace Readarr.Http.Middleware
if (_urlBase.IsNotNullOrWhiteSpace() && context.Request.PathBase.Value.IsNullOrWhiteSpace())
{
context.Response.Redirect($"{_urlBase}{context.Request.Path}{context.Request.QueryString}");
context.Response.StatusCode = 307;
return;
}

3338
yarn.lock

File diff suppressed because it is too large Load Diff