2024-10-05 22:53:22 +02:00
|
|
|
/*
|
|
|
|
|
* Copyright (C) Contributors to the Suwayomi project
|
|
|
|
|
*
|
|
|
|
|
* This Source Code Form is subject to the terms of the Mozilla Public
|
|
|
|
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
|
|
|
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
|
|
|
|
*/
|
|
|
|
|
|
2025-10-11 00:39:44 +02:00
|
|
|
import { d } from 'koration';
|
2025-08-15 22:02:58 +02:00
|
|
|
import { DEFAULT_DEVICE } from '@/features/device/services/Device.ts';
|
|
|
|
|
import { DEFAULT_SORT_SETTINGS } from '@/features/migration/Migration.constants.ts';
|
2025-12-22 21:33:23 +01:00
|
|
|
import {
|
|
|
|
|
GlobalUpdateSkipEntriesSettings,
|
|
|
|
|
ImageProcessingTargetMode,
|
2025-12-22 22:04:05 +01:00
|
|
|
ImageProcessingType,
|
2025-12-22 21:33:23 +01:00
|
|
|
MetadataServerSettings,
|
2025-12-22 22:04:05 +01:00
|
|
|
ServerSettings,
|
2025-12-22 21:33:23 +01:00
|
|
|
} from '@/features/settings/Settings.types.ts';
|
2025-08-16 02:48:46 +02:00
|
|
|
import { GridLayout, TranslationKey } from '@/base/Base.types.ts';
|
|
|
|
|
import { getDefaultLanguages } from '@/base/utils/Languages.ts';
|
|
|
|
|
import { SelectSettingValue, SelectSettingValueDisplayInfo } from '@/base/components/settings/SelectSetting.tsx';
|
2025-12-06 12:59:39 -06:00
|
|
|
import {
|
|
|
|
|
AuthMode,
|
|
|
|
|
KoreaderSyncChecksumMethod,
|
|
|
|
|
KoreaderSyncConflictStrategy,
|
|
|
|
|
WebUiChannel,
|
|
|
|
|
WebUiFlavor,
|
|
|
|
|
WebUiInterface,
|
|
|
|
|
} from '@/lib/graphql/generated/graphql.ts';
|
2025-09-20 18:19:34 +02:00
|
|
|
import { ThemeMode } from '@/features/theme/AppTheme.types.ts';
|
2024-10-05 22:53:22 +02:00
|
|
|
|
2025-06-24 22:22:53 +02:00
|
|
|
export const MANGA_GRID_WIDTH = {
|
|
|
|
|
min: 100,
|
|
|
|
|
max: 1000,
|
|
|
|
|
step: 10,
|
|
|
|
|
default: 300,
|
|
|
|
|
};
|
|
|
|
|
|
2024-10-05 22:53:22 +02:00
|
|
|
export const SERVER_SETTINGS_METADATA_DEFAULT: MetadataServerSettings = {
|
|
|
|
|
// downloads
|
|
|
|
|
deleteChaptersManuallyMarkedRead: false,
|
|
|
|
|
deleteChaptersWhileReading: 0,
|
|
|
|
|
deleteChaptersWithBookmark: false,
|
|
|
|
|
downloadAheadLimit: 0,
|
|
|
|
|
|
|
|
|
|
// library
|
|
|
|
|
showAddToLibraryCategorySelectDialog: true,
|
|
|
|
|
ignoreFilters: false,
|
|
|
|
|
removeMangaFromCategories: false,
|
|
|
|
|
showTabSize: false,
|
2024-12-30 03:49:39 +01:00
|
|
|
showContinueReadingButton: false,
|
|
|
|
|
showDownloadBadge: false,
|
|
|
|
|
showUnreadBadge: false,
|
2025-01-25 00:12:56 +01:00
|
|
|
gridLayout: GridLayout.Compact,
|
2024-10-05 22:53:22 +02:00
|
|
|
|
|
|
|
|
// client
|
|
|
|
|
devices: [DEFAULT_DEVICE],
|
|
|
|
|
|
|
|
|
|
// migration
|
|
|
|
|
migrateChapters: true,
|
|
|
|
|
migrateCategories: true,
|
|
|
|
|
migrateTracking: true,
|
|
|
|
|
deleteChapters: true,
|
|
|
|
|
migrateSortSettings: DEFAULT_SORT_SETTINGS,
|
|
|
|
|
|
|
|
|
|
// browse
|
|
|
|
|
hideLibraryEntries: false,
|
2025-05-09 00:44:48 +02:00
|
|
|
extensionLanguages: getDefaultLanguages(),
|
2025-06-23 02:30:29 +02:00
|
|
|
sourceLanguages: getDefaultLanguages(),
|
2025-04-21 19:18:42 +02:00
|
|
|
showNsfw: true,
|
2025-05-17 23:37:00 +02:00
|
|
|
lastUsedSourceId: null,
|
2025-05-18 00:59:01 +02:00
|
|
|
shouldShowOnlySourcesWithResults: true,
|
2024-10-05 22:53:22 +02:00
|
|
|
|
2025-03-22 01:16:38 +01:00
|
|
|
// history
|
|
|
|
|
hideHistory: false,
|
|
|
|
|
|
2024-10-05 22:53:22 +02:00
|
|
|
// tracking
|
|
|
|
|
updateProgressAfterReading: true,
|
|
|
|
|
updateProgressManualMarkRead: false,
|
|
|
|
|
|
|
|
|
|
// updates
|
|
|
|
|
webUIInformAvailableUpdate: true,
|
|
|
|
|
serverInformAvailableUpdate: true,
|
|
|
|
|
|
|
|
|
|
// themes
|
2025-05-17 21:04:44 +02:00
|
|
|
appTheme: 'default',
|
|
|
|
|
themeMode: ThemeMode.SYSTEM,
|
|
|
|
|
shouldUsePureBlackMode: false,
|
2024-10-05 22:53:22 +02:00
|
|
|
customThemes: {},
|
|
|
|
|
mangaThumbnailBackdrop: true,
|
2025-01-26 03:53:19 +01:00
|
|
|
mangaDynamicColorSchemes: true,
|
2025-06-24 22:22:53 +02:00
|
|
|
mangaGridItemWidth: MANGA_GRID_WIDTH.default,
|
2024-10-05 22:53:22 +02:00
|
|
|
};
|
2025-07-12 01:08:40 +02:00
|
|
|
|
|
|
|
|
const AUTH_MODES = [AuthMode.None].concat(Object.values(AuthMode).filter((mode) => mode !== AuthMode.None));
|
|
|
|
|
const AUTH_MODES_TO_TRANSLATION_KEY: { [mode in AuthMode]: SelectSettingValueDisplayInfo } = {
|
|
|
|
|
[AuthMode.None]: {
|
|
|
|
|
text: 'settings.server.auth.mode.option.none.label.title',
|
|
|
|
|
description: 'settings.server.auth.mode.option.none.label.description',
|
|
|
|
|
disclaimer: 'settings.server.auth.mode.option.none.label.info',
|
|
|
|
|
},
|
|
|
|
|
[AuthMode.BasicAuth]: {
|
|
|
|
|
text: 'settings.server.auth.mode.option.basicAuth.label.title',
|
|
|
|
|
description: 'settings.server.auth.mode.option.basicAuth.label.description',
|
|
|
|
|
},
|
|
|
|
|
[AuthMode.SimpleLogin]: {
|
2025-07-27 00:03:51 +02:00
|
|
|
text: 'settings.server.auth.mode.option.simple_login.label.title',
|
|
|
|
|
description: 'settings.server.auth.mode.option.simple_login.label.description',
|
|
|
|
|
disclaimer: 'settings.server.auth.mode.option.simple_login.label.info',
|
|
|
|
|
},
|
|
|
|
|
[AuthMode.UiLogin]: {
|
|
|
|
|
text: 'settings.server.auth.mode.option.ui_login.label.title',
|
|
|
|
|
description: 'settings.server.auth.mode.option.ui_login.label.description',
|
2025-07-12 01:08:40 +02:00
|
|
|
},
|
|
|
|
|
};
|
|
|
|
|
export const AUTH_MODES_SELECT_VALUES: SelectSettingValue<AuthMode>[] = AUTH_MODES.map((mode) => [
|
|
|
|
|
mode,
|
|
|
|
|
AUTH_MODES_TO_TRANSLATION_KEY[mode],
|
|
|
|
|
]);
|
|
|
|
|
|
|
|
|
|
const WEB_UI_FLAVORS = Object.values(WebUiFlavor);
|
|
|
|
|
const WEB_UI_FLAVOR_TO_TRANSLATION_KEY: { [flavor in WebUiFlavor]: SelectSettingValueDisplayInfo } = {
|
|
|
|
|
[WebUiFlavor.Webui]: {
|
|
|
|
|
text: 'settings.webui.title.webui',
|
|
|
|
|
description: 'settings.webui.flavor.option.webui.label.description',
|
|
|
|
|
disclaimer: 'settings.webui.flavor.label.info',
|
|
|
|
|
},
|
|
|
|
|
[WebUiFlavor.Vui]: {
|
|
|
|
|
text: 'settings.webui.flavor.option.vui.label.title',
|
|
|
|
|
description: 'settings.webui.flavor.option.vui.label.description',
|
|
|
|
|
disclaimer: 'settings.webui.flavor.label.info',
|
|
|
|
|
},
|
|
|
|
|
[WebUiFlavor.Custom]: {
|
|
|
|
|
text: 'settings.webui.flavor.option.custom.label.title',
|
|
|
|
|
description: 'settings.webui.flavor.option.custom.label.description',
|
|
|
|
|
},
|
|
|
|
|
};
|
|
|
|
|
export const WEB_UI_FLAVOR_SELECT_VALUES: SelectSettingValue<WebUiFlavor>[] = WEB_UI_FLAVORS.map((flavor) => [
|
|
|
|
|
flavor,
|
|
|
|
|
WEB_UI_FLAVOR_TO_TRANSLATION_KEY[flavor],
|
|
|
|
|
]);
|
|
|
|
|
|
|
|
|
|
const WEB_UI_CHANNELS = Object.values(WebUiChannel);
|
|
|
|
|
const WEB_UI_CHANNEL_TO_TRANSLATION_KEYS: {
|
|
|
|
|
[channel in WebUiChannel]: SelectSettingValueDisplayInfo;
|
|
|
|
|
} = {
|
|
|
|
|
[WebUiChannel.Bundled]: {
|
|
|
|
|
text: 'settings.webui.channel.option.bundled.label.title',
|
|
|
|
|
description: 'settings.webui.channel.option.bundled.label.description',
|
|
|
|
|
disclaimer: 'settings.webui.flavor.label.info',
|
|
|
|
|
},
|
|
|
|
|
[WebUiChannel.Stable]: {
|
|
|
|
|
text: 'settings.webui.channel.option.stable.label.title',
|
|
|
|
|
description: 'settings.webui.channel.option.stable.label.description',
|
|
|
|
|
disclaimer: 'settings.webui.flavor.label.info',
|
|
|
|
|
},
|
|
|
|
|
[WebUiChannel.Preview]: {
|
|
|
|
|
text: 'settings.webui.channel.option.preview.label.title',
|
|
|
|
|
description: 'settings.webui.channel.option.preview.label.description',
|
|
|
|
|
disclaimer: 'settings.webui.channel.option.preview.label.disclaimer',
|
|
|
|
|
},
|
|
|
|
|
};
|
|
|
|
|
export const WEB_UI_CHANNEL_SELECT_VALUES: SelectSettingValue<WebUiChannel>[] = WEB_UI_CHANNELS.map((channel) => [
|
|
|
|
|
channel,
|
|
|
|
|
WEB_UI_CHANNEL_TO_TRANSLATION_KEYS[channel],
|
|
|
|
|
]);
|
|
|
|
|
|
|
|
|
|
const WEB_UI_INTERFACES = Object.values(WebUiInterface);
|
|
|
|
|
const WEB_UI_INTERFACE_TO_TRANSLATION_KEYS: {
|
|
|
|
|
[webUIInterface in WebUiInterface]: SelectSettingValueDisplayInfo;
|
|
|
|
|
} = {
|
|
|
|
|
[WebUiInterface.Browser]: {
|
|
|
|
|
text: 'settings.webui.interface.option.label.browser',
|
|
|
|
|
description: 'settings.webui.interface.label.description',
|
|
|
|
|
},
|
|
|
|
|
[WebUiInterface.Electron]: {
|
|
|
|
|
text: 'settings.webui.interface.option.label.electron',
|
|
|
|
|
description: 'settings.webui.interface.label.description',
|
|
|
|
|
},
|
|
|
|
|
};
|
|
|
|
|
export const WEB_UI_INTERFACE_SELECT_VALUES: SelectSettingValue<WebUiInterface>[] = WEB_UI_INTERFACES.map(
|
|
|
|
|
(webUIInterface) => [webUIInterface, WEB_UI_INTERFACE_TO_TRANSLATION_KEYS[webUIInterface]],
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
export const GLOBAL_UPDATE_INTERVAL = {
|
2025-10-11 00:39:44 +02:00
|
|
|
default: d(12).hours.inWholeHours,
|
|
|
|
|
min: d(6).hours.inWholeHours,
|
|
|
|
|
max: d(1).months.inWholeHours,
|
2025-07-12 01:08:40 +02:00
|
|
|
};
|
|
|
|
|
|
|
|
|
|
export const GLOBAL_UPDATE_SKIP_ENTRIES_TO_TRANSLATION: {
|
|
|
|
|
[setting in keyof GlobalUpdateSkipEntriesSettings]: TranslationKey;
|
|
|
|
|
} = {
|
|
|
|
|
excludeUnreadChapters: 'library.settings.global_update.entries.label.unread_chapters',
|
|
|
|
|
excludeNotStarted: 'library.settings.global_update.entries.label.not_started',
|
|
|
|
|
excludeCompleted: 'library.settings.global_update.entries.label.completed',
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
export const WEB_UI_UPDATE_INTERVAL = {
|
2025-10-11 00:39:44 +02:00
|
|
|
default: d(23).hours.inWholeHours,
|
|
|
|
|
min: d(1).hours.inWholeHours,
|
|
|
|
|
max: d(23).hours.inWholeHours,
|
2025-07-12 01:08:40 +02:00
|
|
|
};
|
2025-07-27 00:03:51 +02:00
|
|
|
|
|
|
|
|
export const JWT_ACCESS_TOKEN_EXPIRY = {
|
2025-10-11 00:39:44 +02:00
|
|
|
default: d(5).minutes.inWholeMinutes,
|
|
|
|
|
min: d(1).minutes.inWholeMinutes,
|
|
|
|
|
max: d(4).hours.inWholeMinutes,
|
2025-07-27 00:03:51 +02:00
|
|
|
};
|
|
|
|
|
|
|
|
|
|
export const JWT_REFRESH_TOKEN_EXPIRY = {
|
2025-10-11 00:39:44 +02:00
|
|
|
default: d(60).days.inWholeDays,
|
|
|
|
|
min: d(1).days.inWholeDays,
|
|
|
|
|
max: d(1).years.inWholeDays,
|
2025-07-27 00:03:51 +02:00
|
|
|
};
|
2025-09-08 00:24:32 +02:00
|
|
|
|
|
|
|
|
export const KOREADER_SYNC_PERCENTAGE_TOLERANCE = {
|
|
|
|
|
default: 1.0e-15,
|
|
|
|
|
min: 1.0e-15,
|
|
|
|
|
max: 1,
|
2025-09-18 19:20:41 +02:00
|
|
|
step: 0.05,
|
2025-09-08 00:24:32 +02:00
|
|
|
};
|
2025-12-06 12:59:39 -06:00
|
|
|
|
|
|
|
|
export const KOREADER_SYNC_CONFLICT_STRATEGIES = Object.values(KoreaderSyncConflictStrategy);
|
|
|
|
|
export const KOREADER_SYNC_CONFLICT_STRATEGY_TO_TRANSLATION_KEYS: Record<
|
|
|
|
|
KoreaderSyncConflictStrategy,
|
|
|
|
|
SelectSettingValueDisplayInfo
|
|
|
|
|
> = {
|
|
|
|
|
[KoreaderSyncConflictStrategy.Disabled]: {
|
|
|
|
|
text: 'settings.server.koreader.sync.strategy.option.disabled',
|
|
|
|
|
},
|
|
|
|
|
[KoreaderSyncConflictStrategy.KeepLocal]: {
|
|
|
|
|
text: 'settings.server.koreader.sync.strategy.option.keep_local',
|
|
|
|
|
},
|
|
|
|
|
[KoreaderSyncConflictStrategy.KeepRemote]: {
|
|
|
|
|
text: 'settings.server.koreader.sync.strategy.option.keep_remote',
|
|
|
|
|
},
|
|
|
|
|
[KoreaderSyncConflictStrategy.Prompt]: {
|
|
|
|
|
text: 'settings.server.koreader.sync.strategy.option.prompt',
|
|
|
|
|
},
|
|
|
|
|
};
|
|
|
|
|
export const KOREADER_SYNC_CONFLICT_STRATEGY_SELECT_VALUES: SelectSettingValue<KoreaderSyncConflictStrategy>[] =
|
|
|
|
|
KOREADER_SYNC_CONFLICT_STRATEGIES.map((strategy) => [
|
|
|
|
|
strategy,
|
|
|
|
|
KOREADER_SYNC_CONFLICT_STRATEGY_TO_TRANSLATION_KEYS[strategy],
|
|
|
|
|
]);
|
|
|
|
|
|
|
|
|
|
export const KOREADER_SYNC_CHECKSUM_METHODES = Object.values(KoreaderSyncChecksumMethod);
|
|
|
|
|
export const KOREADER_SYNC_CHECKSUM_METHOD_TO_TRANSLATION_KEYS: Record<
|
|
|
|
|
KoreaderSyncChecksumMethod,
|
|
|
|
|
SelectSettingValueDisplayInfo
|
|
|
|
|
> = {
|
|
|
|
|
[KoreaderSyncChecksumMethod.Binary]: {
|
|
|
|
|
text: 'settings.server.koreader.sync.check_sum_method.binary',
|
|
|
|
|
},
|
|
|
|
|
[KoreaderSyncChecksumMethod.Filename]: {
|
|
|
|
|
text: 'settings.server.koreader.sync.check_sum_method.filename',
|
|
|
|
|
},
|
|
|
|
|
};
|
|
|
|
|
export const KOREADER_SYNC_CHECKSUM_METHOD_SELECT_VALUES: SelectSettingValue<KoreaderSyncChecksumMethod>[] =
|
|
|
|
|
KOREADER_SYNC_CHECKSUM_METHODES.map((method) => [
|
|
|
|
|
method,
|
|
|
|
|
KOREADER_SYNC_CHECKSUM_METHOD_TO_TRANSLATION_KEYS[method],
|
|
|
|
|
]);
|
2025-12-22 21:11:12 +01:00
|
|
|
|
|
|
|
|
export const IMAGE_PROCESSING_COMPRESSION = {
|
|
|
|
|
min: 0,
|
|
|
|
|
max: 1,
|
|
|
|
|
step: 0.01,
|
|
|
|
|
};
|
|
|
|
|
export const IMAGE_PROCESSING_CALL_TIMEOUT = {
|
|
|
|
|
min: d(10).seconds.inWholeSeconds,
|
|
|
|
|
max: d(10).minutes.inWholeSeconds,
|
|
|
|
|
step: d(10).seconds.inWholeSeconds,
|
|
|
|
|
};
|
|
|
|
|
export const IMAGE_PROCESSING_CONNECT_TIMEOUT = {
|
|
|
|
|
min: d(10).seconds.inWholeSeconds,
|
|
|
|
|
max: d(10).minutes.inWholeSeconds,
|
|
|
|
|
step: d(10).seconds.inWholeSeconds,
|
|
|
|
|
};
|
2025-12-22 21:33:23 +01:00
|
|
|
|
|
|
|
|
const IMAGE_PROCESSING_TARGET_MODES = Object.values(ImageProcessingTargetMode);
|
|
|
|
|
const IMAGE_PROCESSING_TARGET_MODES_TO_TRANSLATION_KEY: {
|
|
|
|
|
[flavor in ImageProcessingTargetMode]: SelectSettingValueDisplayInfo;
|
|
|
|
|
} = {
|
|
|
|
|
[ImageProcessingTargetMode.IMAGE]: {
|
|
|
|
|
text: 'download.settings.conversion.target_modes.image.title',
|
|
|
|
|
description: 'download.settings.conversion.target_modes.image.description',
|
|
|
|
|
},
|
|
|
|
|
[ImageProcessingTargetMode.URL]: {
|
|
|
|
|
text: 'download.settings.conversion.target_modes.url.title',
|
|
|
|
|
description: 'download.settings.conversion.target_modes.image.description',
|
|
|
|
|
},
|
|
|
|
|
};
|
|
|
|
|
export const IMAGE_PROCESSING_TARGET_MODES_SELECT_VALUES: SelectSettingValue<ImageProcessingTargetMode>[] =
|
|
|
|
|
IMAGE_PROCESSING_TARGET_MODES.map((mode) => [mode, IMAGE_PROCESSING_TARGET_MODES_TO_TRANSLATION_KEY[mode]]);
|
|
|
|
|
|
|
|
|
|
export const IMAGE_PROCESSING_INPUT_WIDTH = 250;
|
|
|
|
|
export const DEFAULT_MIME_TYPE = 'default';
|
|
|
|
|
export const MIME_TYPE_PREFIX = 'image/';
|
2025-12-22 22:04:05 +01:00
|
|
|
|
|
|
|
|
export const IMAGE_PROCESSING_TYPE_TO_TRANSLATION: Record<ImageProcessingType, TranslationKey> = {
|
|
|
|
|
[ImageProcessingType.DOWNLOAD]: 'download.settings.conversion.title',
|
|
|
|
|
[ImageProcessingType.SERVE]: 'settings.images.processing.serve.title',
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
export const IMAGE_PROCESSING_TYPE_TO_SETTING: Record<
|
|
|
|
|
ImageProcessingType,
|
|
|
|
|
Extract<keyof ServerSettings, 'downloadConversions' | 'serveConversions'>
|
|
|
|
|
> = {
|
|
|
|
|
[ImageProcessingType.DOWNLOAD]: 'downloadConversions',
|
|
|
|
|
[ImageProcessingType.SERVE]: 'serveConversions',
|
|
|
|
|
};
|