mirror of
https://github.com/fallenbagel/jellyseerr.git
synced 2026-01-01 04:08:45 -05:00
feat(settings): add settings for custom DNS servers and IPv4 resolution first (#1266)
* feat(settings): add settings for custom DNS servers and IPv4 resolution first This PR adds settings to change the DNS servers Jellyseerr uses and to force Jellyseerr to resolve DNS queries using IPv4 first. These settings aim to make it easier for less experienced users to fix network errors related to DNS resolution. * style: fix missing newline
This commit is contained in:
@@ -23,6 +23,8 @@
|
|||||||
"mediaServerType": 1,
|
"mediaServerType": 1,
|
||||||
"partialRequestsEnabled": true,
|
"partialRequestsEnabled": true,
|
||||||
"enableSpecialEpisodes": false,
|
"enableSpecialEpisodes": false,
|
||||||
|
"forceIpv4First": false,
|
||||||
|
"dnsServers": "",
|
||||||
"locale": "en"
|
"locale": "en"
|
||||||
},
|
},
|
||||||
"plex": {
|
"plex": {
|
||||||
|
|||||||
@@ -191,6 +191,12 @@ components:
|
|||||||
enableSpecialEpisodes:
|
enableSpecialEpisodes:
|
||||||
type: boolean
|
type: boolean
|
||||||
example: false
|
example: false
|
||||||
|
forceIpv4First:
|
||||||
|
type: boolean
|
||||||
|
example: false
|
||||||
|
dnsServers:
|
||||||
|
type: string
|
||||||
|
example: '1.1.1.1'
|
||||||
PlexLibrary:
|
PlexLibrary:
|
||||||
type: object
|
type: object
|
||||||
properties:
|
properties:
|
||||||
|
|||||||
@@ -41,11 +41,6 @@ import path from 'path';
|
|||||||
import swaggerUi from 'swagger-ui-express';
|
import swaggerUi from 'swagger-ui-express';
|
||||||
import YAML from 'yamljs';
|
import YAML from 'yamljs';
|
||||||
|
|
||||||
if (process.env.forceIpv4First === 'true') {
|
|
||||||
dns.setDefaultResultOrder('ipv4first');
|
|
||||||
net.setDefaultAutoSelectFamily(false);
|
|
||||||
}
|
|
||||||
|
|
||||||
const API_SPEC_PATH = path.join(__dirname, '../overseerr-api.yml');
|
const API_SPEC_PATH = path.join(__dirname, '../overseerr-api.yml');
|
||||||
|
|
||||||
logger.info(`Starting Overseerr version ${getAppVersion()}`);
|
logger.info(`Starting Overseerr version ${getAppVersion()}`);
|
||||||
@@ -79,6 +74,18 @@ app
|
|||||||
const settings = await getSettings().load();
|
const settings = await getSettings().load();
|
||||||
restartFlag.initializeSettings(settings.main);
|
restartFlag.initializeSettings(settings.main);
|
||||||
|
|
||||||
|
// Check if we force IPv4 first
|
||||||
|
if (process.env.forceIpv4First === 'true' || settings.main.forceIpv4First) {
|
||||||
|
dns.setDefaultResultOrder('ipv4first');
|
||||||
|
net.setDefaultAutoSelectFamily(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (settings.main.dnsServers.trim() !== '') {
|
||||||
|
dns.setServers(
|
||||||
|
settings.main.dnsServers.split(',').map((server) => server.trim())
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
// Register HTTP proxy
|
// Register HTTP proxy
|
||||||
if (settings.main.proxy.enabled) {
|
if (settings.main.proxy.enabled) {
|
||||||
await createCustomProxyAgent(settings.main.proxy);
|
await createCustomProxyAgent(settings.main.proxy);
|
||||||
|
|||||||
@@ -132,6 +132,8 @@ export interface MainSettings {
|
|||||||
mediaServerType: number;
|
mediaServerType: number;
|
||||||
partialRequestsEnabled: boolean;
|
partialRequestsEnabled: boolean;
|
||||||
enableSpecialEpisodes: boolean;
|
enableSpecialEpisodes: boolean;
|
||||||
|
forceIpv4First: boolean;
|
||||||
|
dnsServers: string;
|
||||||
locale: string;
|
locale: string;
|
||||||
proxy: ProxySettings;
|
proxy: ProxySettings;
|
||||||
}
|
}
|
||||||
@@ -346,6 +348,8 @@ class Settings {
|
|||||||
mediaServerType: MediaServerType.NOT_CONFIGURED,
|
mediaServerType: MediaServerType.NOT_CONFIGURED,
|
||||||
partialRequestsEnabled: true,
|
partialRequestsEnabled: true,
|
||||||
enableSpecialEpisodes: false,
|
enableSpecialEpisodes: false,
|
||||||
|
forceIpv4First: false,
|
||||||
|
dnsServers: '',
|
||||||
locale: 'en',
|
locale: 'en',
|
||||||
proxy: {
|
proxy: {
|
||||||
enabled: false,
|
enabled: false,
|
||||||
|
|||||||
@@ -14,7 +14,9 @@ class RestartFlag {
|
|||||||
return (
|
return (
|
||||||
this.settings.csrfProtection !== settings.csrfProtection ||
|
this.settings.csrfProtection !== settings.csrfProtection ||
|
||||||
this.settings.trustProxy !== settings.trustProxy ||
|
this.settings.trustProxy !== settings.trustProxy ||
|
||||||
this.settings.proxy.enabled !== settings.proxy.enabled
|
this.settings.proxy.enabled !== settings.proxy.enabled ||
|
||||||
|
this.settings.forceIpv4First !== settings.forceIpv4First ||
|
||||||
|
this.settings.dnsServers !== settings.dnsServers
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -57,6 +57,12 @@ const messages = defineMessages('components.Settings.SettingsMain', {
|
|||||||
validationApplicationUrlTrailingSlash: 'URL must not end in a trailing slash',
|
validationApplicationUrlTrailingSlash: 'URL must not end in a trailing slash',
|
||||||
partialRequestsEnabled: 'Allow Partial Series Requests',
|
partialRequestsEnabled: 'Allow Partial Series Requests',
|
||||||
enableSpecialEpisodes: 'Allow Special Episodes Requests',
|
enableSpecialEpisodes: 'Allow Special Episodes Requests',
|
||||||
|
forceIpv4First: 'IPv4 Resolution First',
|
||||||
|
forceIpv4FirstTip:
|
||||||
|
'Force Jellyseerr to resolve IPv4 addresses first instead of IPv6',
|
||||||
|
dnsServers: 'Custom DNS Servers',
|
||||||
|
dnsServersTip:
|
||||||
|
'Comma-separated list of custom DNS servers, e.g. "1.1.1.1,[2606:4700:4700::1111]"',
|
||||||
locale: 'Display Language',
|
locale: 'Display Language',
|
||||||
proxyEnabled: 'HTTP(S) Proxy',
|
proxyEnabled: 'HTTP(S) Proxy',
|
||||||
proxyHostname: 'Proxy Hostname',
|
proxyHostname: 'Proxy Hostname',
|
||||||
@@ -160,6 +166,8 @@ const SettingsMain = () => {
|
|||||||
streamingRegion: data?.streamingRegion || 'US',
|
streamingRegion: data?.streamingRegion || 'US',
|
||||||
partialRequestsEnabled: data?.partialRequestsEnabled,
|
partialRequestsEnabled: data?.partialRequestsEnabled,
|
||||||
enableSpecialEpisodes: data?.enableSpecialEpisodes,
|
enableSpecialEpisodes: data?.enableSpecialEpisodes,
|
||||||
|
forceIpv4First: data?.forceIpv4First,
|
||||||
|
dnsServers: data?.dnsServers,
|
||||||
trustProxy: data?.trustProxy,
|
trustProxy: data?.trustProxy,
|
||||||
cacheImages: data?.cacheImages,
|
cacheImages: data?.cacheImages,
|
||||||
proxyEnabled: data?.proxy?.enabled,
|
proxyEnabled: data?.proxy?.enabled,
|
||||||
@@ -191,6 +199,8 @@ const SettingsMain = () => {
|
|||||||
originalLanguage: values.originalLanguage,
|
originalLanguage: values.originalLanguage,
|
||||||
partialRequestsEnabled: values.partialRequestsEnabled,
|
partialRequestsEnabled: values.partialRequestsEnabled,
|
||||||
enableSpecialEpisodes: values.enableSpecialEpisodes,
|
enableSpecialEpisodes: values.enableSpecialEpisodes,
|
||||||
|
forceIpv4First: values.forceIpv4First,
|
||||||
|
dnsServers: values.dnsServers,
|
||||||
trustProxy: values.trustProxy,
|
trustProxy: values.trustProxy,
|
||||||
cacheImages: values.cacheImages,
|
cacheImages: values.cacheImages,
|
||||||
proxy: {
|
proxy: {
|
||||||
@@ -524,6 +534,55 @@ const SettingsMain = () => {
|
|||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<div className="form-row">
|
||||||
|
<label htmlFor="forceIpv4First" className="checkbox-label">
|
||||||
|
<span className="mr-2">
|
||||||
|
{intl.formatMessage(messages.forceIpv4First)}
|
||||||
|
</span>
|
||||||
|
<SettingsBadge badgeType="advanced" className="mr-2" />
|
||||||
|
<SettingsBadge badgeType="restartRequired" />
|
||||||
|
<span className="label-tip">
|
||||||
|
{intl.formatMessage(messages.forceIpv4FirstTip)}
|
||||||
|
</span>
|
||||||
|
</label>
|
||||||
|
<div className="form-input-area">
|
||||||
|
<Field
|
||||||
|
type="checkbox"
|
||||||
|
id="forceIpv4First"
|
||||||
|
name="forceIpv4First"
|
||||||
|
onChange={() => {
|
||||||
|
setFieldValue('forceIpv4First', !values.forceIpv4First);
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div className="form-row">
|
||||||
|
<label htmlFor="dnsServers" className="checkbox-label">
|
||||||
|
<span className="mr-2">
|
||||||
|
{intl.formatMessage(messages.dnsServers)}
|
||||||
|
</span>
|
||||||
|
<SettingsBadge badgeType="advanced" className="mr-2" />
|
||||||
|
<SettingsBadge badgeType="restartRequired" />
|
||||||
|
<span className="label-tip">
|
||||||
|
{intl.formatMessage(messages.dnsServersTip)}
|
||||||
|
</span>
|
||||||
|
</label>
|
||||||
|
<div className="form-input-area">
|
||||||
|
<div className="form-input-field">
|
||||||
|
<Field
|
||||||
|
id="dnsServers"
|
||||||
|
name="dnsServers"
|
||||||
|
type="text"
|
||||||
|
inputMode="url"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
{errors.dnsServers &&
|
||||||
|
touched.dnsServers &&
|
||||||
|
typeof errors.dnsServers === 'string' && (
|
||||||
|
<div className="error">{errors.dnsServers}</div>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
<div className="form-row">
|
<div className="form-row">
|
||||||
<label htmlFor="proxyEnabled" className="checkbox-label">
|
<label htmlFor="proxyEnabled" className="checkbox-label">
|
||||||
<span className="mr-2">
|
<span className="mr-2">
|
||||||
|
|||||||
@@ -246,6 +246,7 @@
|
|||||||
"components.Login.initialsigningin": "Connecting…",
|
"components.Login.initialsigningin": "Connecting…",
|
||||||
"components.Login.invalidurlerror": "Unable to connect to {mediaServerName} server.",
|
"components.Login.invalidurlerror": "Unable to connect to {mediaServerName} server.",
|
||||||
"components.Login.loginerror": "Something went wrong while trying to sign in.",
|
"components.Login.loginerror": "Something went wrong while trying to sign in.",
|
||||||
|
"components.Login.noadminerror": "No admin user found on the server.",
|
||||||
"components.Login.password": "Password",
|
"components.Login.password": "Password",
|
||||||
"components.Login.port": "Port",
|
"components.Login.port": "Port",
|
||||||
"components.Login.save": "Add",
|
"components.Login.save": "Add",
|
||||||
@@ -919,7 +920,11 @@
|
|||||||
"components.Settings.SettingsMain.csrfProtectionTip": "Set external API access to read-only (requires HTTPS)",
|
"components.Settings.SettingsMain.csrfProtectionTip": "Set external API access to read-only (requires HTTPS)",
|
||||||
"components.Settings.SettingsMain.discoverRegion": "Discover Region",
|
"components.Settings.SettingsMain.discoverRegion": "Discover Region",
|
||||||
"components.Settings.SettingsMain.discoverRegionTip": "Filter content by regional availability",
|
"components.Settings.SettingsMain.discoverRegionTip": "Filter content by regional availability",
|
||||||
|
"components.Settings.SettingsMain.dnsServers": "Custom DNS Servers",
|
||||||
|
"components.Settings.SettingsMain.dnsServersTip": "Comma-separated list of custom DNS servers, e.g. \"1.1.1.1,[2606:4700:4700::1111]\"",
|
||||||
"components.Settings.SettingsMain.enableSpecialEpisodes": "Allow Special Episodes Requests",
|
"components.Settings.SettingsMain.enableSpecialEpisodes": "Allow Special Episodes Requests",
|
||||||
|
"components.Settings.SettingsMain.forceIpv4First": "IPv4 Resolution First",
|
||||||
|
"components.Settings.SettingsMain.forceIpv4FirstTip": "Force Jellyseerr to resolve IPv4 addresses first instead of IPv6",
|
||||||
"components.Settings.SettingsMain.general": "General",
|
"components.Settings.SettingsMain.general": "General",
|
||||||
"components.Settings.SettingsMain.generalsettings": "General Settings",
|
"components.Settings.SettingsMain.generalsettings": "General Settings",
|
||||||
"components.Settings.SettingsMain.generalsettingsDescription": "Configure global and default settings for Jellyseerr.",
|
"components.Settings.SettingsMain.generalsettingsDescription": "Configure global and default settings for Jellyseerr.",
|
||||||
|
|||||||
Reference in New Issue
Block a user