New: Allow major version updates to be installed

(cherry picked from commit 0e95ba2021b23cc65bce0a0620dd48e355250dab)
pull/3800/head
Mark McDowall 6 months ago committed by Bogdan
parent cfccb4f9c3
commit e7d7bc79f4

@ -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

@ -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;
}

@ -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;

@ -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;

@ -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;

@ -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;

@ -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;

@ -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;

@ -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;
}

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

@ -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;

@ -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;

@ -300,7 +300,7 @@
"ChangeFileDate": "تغيير تاريخ الملف",
"CertificateValidationHelpText": "تغيير مدى صرامة التحقق من صحة شهادة HTTPS",
"CertificateValidation": "التحقق من صحة الشهادة",
"CancelMessageText": "هل أنت متأكد أنك تريد إلغاء هذه المهمة المعلقة؟",
"CancelPendingTask": "هل أنت متأكد أنك تريد إلغاء هذه المهمة المعلقة؟",
"Cancel": "إلغاء",
"CalendarWeekColumnHeaderHelpText": "يظهر فوق كل عمود عندما يكون الأسبوع هو العرض النشط",
"Calendar": "التقويم",

@ -36,7 +36,7 @@
"Calendar": "Календар",
"CalendarWeekColumnHeaderHelpText": "Показва се над всяка колона, когато седмицата е активният изглед",
"Cancel": "Отказ",
"CancelMessageText": "Наистина ли искате да отмените тази чакаща задача?",
"CancelPendingTask": "Наистина ли искате да отмените тази чакаща задача?",
"CertificateValidation": "Валидиране на сертификат",
"CertificateValidationHelpText": "Променете колко строго е валидирането на HTTPS сертифициране",
"ChangeFileDate": "Промяна на датата на файла",

@ -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",

@ -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",

@ -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",

@ -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",

@ -40,7 +40,7 @@
"Calendar": "Ημερολόγιο",
"CalendarWeekColumnHeaderHelpText": "Εμφανίζεται πάνω από κάθε στήλη όταν η εβδομάδα είναι η ενεργή προβολή",
"Cancel": "Ακύρωση",
"CancelMessageText": "Είστε βέβαιοι ότι θέλετε να ακυρώσετε αυτήν την εργασία σε εκκρεμότητα;",
"CancelPendingTask": "Είστε βέβαιοι ότι θέλετε να ακυρώσετε αυτήν την εργασία σε εκκρεμότητα;",
"CertificateValidation": "Επικύρωση πιστοποιητικού",
"CertificateValidationHelpText": "Αλλάξτε πόσο αυστηρή είναι η επικύρωση πιστοποίησης HTTPS.",
"ChangeFileDate": "Αλλαγή ημερομηνίας αρχείου",

@ -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)",
@ -137,7 +138,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 +198,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 +295,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 +360,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 +484,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 +685,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 +718,7 @@
"PosterSize": "Poster Size",
"PreviewRename": "Preview Rename",
"PreviewRetag": "Preview Retag",
"PreviouslyInstalled": "Previously Installed",
"Profiles": "Profiles",
"ProfilesSettingsSummary": "Quality, Metadata, Delay, and Release profiles",
"Progress": "Progress",
@ -1051,6 +1064,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}'.",

@ -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",

@ -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",

@ -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",

@ -25,7 +25,7 @@
"BypassProxyForLocalAddresses": "עקיפת פרוקסי לכתובות מקומיות",
"Calendar": "לוּחַ שָׁנָה",
"CalendarWeekColumnHeaderHelpText": "מוצג מעל כל עמודה כאשר השבוע היא התצוגה הפעילה",
"CancelMessageText": "האם אתה בטוח שברצונך לבטל משימה זו בהמתנה?",
"CancelPendingTask": "האם אתה בטוח שברצונך לבטל משימה זו בהמתנה?",
"CertificateValidation": "אימות תעודה",
"CertificateValidationHelpText": "שנה את מידת אימות ההסמכה של HTTPS",
"ChangeFileDate": "שנה את תאריך הקובץ",

@ -31,7 +31,7 @@
"Calendar": "पंचांग",
"CalendarWeekColumnHeaderHelpText": "प्रत्येक स्तंभ के ऊपर दिखाया गया जब सप्ताह सक्रिय दृश्य होता है",
"Cancel": "रद्द करना",
"CancelMessageText": "क्या आप वाकई इस लंबित कार्य को रद्द करना चाहते हैं?",
"CancelPendingTask": "क्या आप वाकई इस लंबित कार्य को रद्द करना चाहते हैं?",
"CertificateValidation": "प्रमाणपत्र सत्यापन",
"CertificateValidationHelpText": "बदलें कि HTTPS प्रमाणन सत्यापन कितना सख्त है",
"ChangeFileDate": "फ़ाइल दिनांक बदलें",

@ -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}?",

@ -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",

@ -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",

@ -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",

@ -349,7 +349,7 @@
"Calendar": "カレンダー",
"CalendarWeekColumnHeaderHelpText": "週がアクティブビューの場合、各列の上に表示されます",
"Cancel": "キャンセル",
"CancelMessageText": "この保留中のタスクをキャンセルしてもよろしいですか?",
"CancelPendingTask": "この保留中のタスクをキャンセルしてもよろしいですか?",
"CertificateValidation": "証明書の検証",
"CertificateValidationHelpText": "HTTPS認証検証の厳密さを変更する",
"ChangeFileDate": "ファイルの日付を変更する",

@ -88,7 +88,7 @@
"Calendar": "달력",
"CalendarWeekColumnHeaderHelpText": "주가 활성보기 일 때 각 열 위에 표시됩니다.",
"Cancel": "취소",
"CancelMessageText": "이 보류중인 작업을 취소 하시겠습니까?",
"CancelPendingTask": "이 보류중인 작업을 취소 하시겠습니까?",
"CertificateValidation": "인증서 검증",
"CertificateValidationHelpText": "HTTPS 인증 유효성 검사의 엄격한 방법 변경",
"ChangeFileDate": "파일 날짜 변경",

@ -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,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",

@ -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",

@ -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",

@ -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",

@ -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ă",

@ -45,7 +45,7 @@
"Calendar": "Календарь",
"CalendarWeekColumnHeaderHelpText": "Отображается над каждым столбцом, когда неделя активна",
"Cancel": "Отменить",
"CancelMessageText": "Вы уверены, что хотите убрать данную задачу из очереди?",
"CancelPendingTask": "Вы уверены, что хотите убрать данную задачу из очереди?",
"CertificateValidation": "Проверка сертификата",
"CertificateValidationHelpText": "Измените строгую проверку сертификации HTTPS. Не меняйте, если вы не понимаете риски.",
"ChangeFileDate": "Изменить дату файла",

@ -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",

@ -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",

@ -47,7 +47,7 @@
"Calendar": "ปฏิทิน",
"CalendarWeekColumnHeaderHelpText": "แสดงอยู่เหนือแต่ละคอลัมน์เมื่อสัปดาห์เป็นมุมมองที่ใช้งานอยู่",
"Cancel": "ยกเลิก",
"CancelMessageText": "แน่ใจไหมว่าต้องการยกเลิกงานที่รอดำเนินการนี้",
"CancelPendingTask": "แน่ใจไหมว่าต้องการยกเลิกงานที่รอดำเนินการนี้",
"CertificateValidation": "การตรวจสอบใบรับรอง",
"CertificateValidationHelpText": "เปลี่ยนวิธีการตรวจสอบการรับรอง HTTPS ที่เข้มงวด",
"ChangeFileDate": "เปลี่ยนวันที่ของไฟล์",

@ -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",

@ -56,7 +56,7 @@
"BindAddressHelpText": "Дійсна адреса IPv4 або '*' для всіх інтерфейсів",
"Blocklist": "Чорний список",
"BlocklistRelease": "Реліз із чорного списку",
"CancelMessageText": "Ви впевнені, що хочете скасувати це незавершене завдання?",
"CancelPendingTask": "Ви впевнені, що хочете скасувати це незавершене завдання?",
"ChownGroupHelpText": "Назва групи або gid. Використовуйте gid для віддалених файлових систем.",
"ChownGroupHelpTextWarning": "Це працює лише в тому випадку, якщо власником файлу є користувач, на якому працює Radarr. Краще переконатися, що клієнт для завантаження використовує ту саму групу, що й Radarr.",
"DeleteReleaseProfile": "Видалити профіль випуску",

@ -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",

@ -33,7 +33,7 @@
"Calendar": "日历",
"CalendarWeekColumnHeaderHelpText": "当使用周视图时显示上面的每一列",
"Cancel": "取消",
"CancelMessageText": "您确定要取消这个挂起的任务吗?",
"CancelPendingTask": "您确定要取消这个挂起的任务吗?",
"CertificateValidation": "验证证书",
"CertificateValidationHelpText": "改变HTTPS证书验证的严格程度。不要更改除非您了解风险。",
"ChangeFileDate": "修改文件日期",

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

@ -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;
}

@ -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;
@ -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)
{

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

@ -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)

Loading…
Cancel
Save