1
0
Fork 0
mirror of https://github.com/jellyfin/jellyfin-web synced 2025-03-30 19:56:21 +00:00

Clean up network settings page

- remove HTTPS mode dropdown and split it into two checkboxes: EnableHttps and RequireHttps (IsBehindProxy is no longer a setting on the server)
- Reorganize settings on page
   - Create a fieldset for HTTPS settings
   - Create a fieldset for remote connection settings
   - Move baseUrl out of remote connection settings at closer to the top of the page
This commit is contained in:
Mark Monteiro 2020-04-26 17:17:59 -04:00
parent 47d8ef7fc2
commit ac62b82828
3 changed files with 95 additions and 121 deletions

View file

@ -9,7 +9,7 @@ define(["loading", "libraryMenu", "globalize", "emby-checkbox", "emby-select"],
var validationResult = getValidationAlert(form); var validationResult = getValidationAlert(form);
if (validationResult) { if (validationResult) {
alertText(validationResult); showAlertText(validationResult);
return; return;
} }
@ -29,35 +29,10 @@ define(["loading", "libraryMenu", "globalize", "emby-checkbox", "emby-select"],
config.IsRemoteIPFilterBlacklist = "blacklist" === form.querySelector("#selectExternalAddressFilterMode").value; config.IsRemoteIPFilterBlacklist = "blacklist" === form.querySelector("#selectExternalAddressFilterMode").value;
config.PublicPort = form.querySelector("#txtPublicPort").value; config.PublicPort = form.querySelector("#txtPublicPort").value;
config.PublicHttpsPort = form.querySelector("#txtPublicHttpsPort").value; config.PublicHttpsPort = form.querySelector("#txtPublicHttpsPort").value;
var httpsMode = form.querySelector("#selectHttpsMode").value;
switch (httpsMode) {
case "proxy":
config.EnableHttps = true;
config.RequireHttps = false;
config.IsBehindProxy = true;
break;
case "required":
config.EnableHttps = true;
config.RequireHttps = true;
config.IsBehindProxy = false;
break;
case "enabled":
config.EnableHttps = true;
config.RequireHttps = false;
config.IsBehindProxy = false;
break;
default:
config.EnableHttps = false;
config.RequireHttps = false;
config.IsBehindProxy = false;
}
config.HttpsPortNumber = form.querySelector("#txtHttpsPort").value;
config.HttpServerPortNumber = form.querySelector("#txtPortNumber").value; config.HttpServerPortNumber = form.querySelector("#txtPortNumber").value;
config.HttpsPortNumber = form.querySelector("#txtHttpsPort").value;
config.EnableHttps = form.querySelector("#chkEnableHttps").checked;
config.RequireHttps = form.querySelector("#chkRequireHttps").checked;
config.EnableUPnP = enableUpnp; config.EnableUPnP = enableUpnp;
config.BaseUrl = form.querySelector("#txtBaseUrl").value; config.BaseUrl = form.querySelector("#txtBaseUrl").value;
config.EnableRemoteAccess = form.querySelector("#chkRemoteAccess").checked; config.EnableRemoteAccess = form.querySelector("#chkRemoteAccess").checked;
@ -90,23 +65,20 @@ define(["loading", "libraryMenu", "globalize", "emby-checkbox", "emby-select"],
} }
function validateHttps(form) { function validateHttps(form) {
var remoteAccess = form.querySelector("#chkRemoteAccess").checked;
var certPath = form.querySelector("#txtCertificatePath").value || null; var certPath = form.querySelector("#txtCertificatePath").value || null;
var httpsMode = form.querySelector("#selectHttpsMode").value; var httpsEnabled = form.querySelector("#chkEnableHttps").checked;
if (httpsEnabled && !certPath) {
return showAlertText({
title: globalize.translate("TitleHostingSettings"),
text: globalize.translate("HttpsRequiresCert")
}).then(Promise.reject);
}
if (!remoteAccess || ("enabled" !== httpsMode && "required" !== httpsMode || certPath)) {
return Promise.resolve(); return Promise.resolve();
} }
return new Promise(function (resolve, reject) { function showAlertText(options) {
return alertText({
title: globalize.translate("TitleHostingSettings"),
text: globalize.translate("HttpsRequiresCert")
}).then(reject, reject);
});
}
function alertText(options) {
return new Promise(function (resolve, reject) { return new Promise(function (resolve, reject) {
require(["alert"], function (alert) { require(["alert"], function (alert) {
alert(options).then(resolve, reject); alert(options).then(resolve, reject);
@ -116,7 +88,7 @@ define(["loading", "libraryMenu", "globalize", "emby-checkbox", "emby-select"],
function confirmSelections(localAddress, enableUpnp, callback) { function confirmSelections(localAddress, enableUpnp, callback) {
if (localAddress || !enableUpnp) { if (localAddress || !enableUpnp) {
alertText({ showAlertText({
title: globalize.translate("TitleHostingSettings"), title: globalize.translate("TitleHostingSettings"),
text: globalize.translate("SettingsWarning") text: globalize.translate("SettingsWarning")
}).then(callback); }).then(callback);
@ -135,19 +107,9 @@ define(["loading", "libraryMenu", "globalize", "emby-checkbox", "emby-select"],
page.querySelector("#txtExternalAddressFilter").value = (config.RemoteIPFilter || []).join(", "); page.querySelector("#txtExternalAddressFilter").value = (config.RemoteIPFilter || []).join(", ");
page.querySelector("#selectExternalAddressFilterMode").value = config.IsRemoteIPFilterBlacklist ? "blacklist" : "whitelist"; page.querySelector("#selectExternalAddressFilterMode").value = config.IsRemoteIPFilterBlacklist ? "blacklist" : "whitelist";
page.querySelector("#chkRemoteAccess").checked = null == config.EnableRemoteAccess || config.EnableRemoteAccess; page.querySelector("#chkRemoteAccess").checked = null == config.EnableRemoteAccess || config.EnableRemoteAccess;
var selectHttpsMode = page.querySelector("#selectHttpsMode");
if (config.IsBehindProxy) {
selectHttpsMode.value = "proxy";
} else if (config.RequireHttps) {
selectHttpsMode.value = "required";
} else if (config.EnableHttps) {
selectHttpsMode.value = "enabled";
} else {
selectHttpsMode.value = "disabled";
}
page.querySelector("#txtHttpsPort").value = config.HttpsPortNumber; page.querySelector("#txtHttpsPort").value = config.HttpsPortNumber;
page.querySelector("#chkEnableHttps").checked = config.EnableHttps;
page.querySelector("#chkRequireHttps").checked = config.RequireHttps;
page.querySelector("#txtBaseUrl").value = config.BaseUrl || ""; page.querySelector("#txtBaseUrl").value = config.BaseUrl || "";
var txtCertificatePath = page.querySelector("#txtCertificatePath"); var txtCertificatePath = page.querySelector("#txtCertificatePath");
txtCertificatePath.value = config.CertificatePath || ""; txtCertificatePath.value = config.CertificatePath || "";
@ -163,18 +125,12 @@ define(["loading", "libraryMenu", "globalize", "emby-checkbox", "emby-select"],
view.querySelector(".fldExternalAddressFilterMode").classList.remove("hide"); view.querySelector(".fldExternalAddressFilterMode").classList.remove("hide");
view.querySelector(".fldPublicPort").classList.remove("hide"); view.querySelector(".fldPublicPort").classList.remove("hide");
view.querySelector(".fldPublicHttpsPort").classList.remove("hide"); view.querySelector(".fldPublicHttpsPort").classList.remove("hide");
view.querySelector(".fldCertificatePath").classList.remove("hide");
view.querySelector(".fldCertPassword").classList.remove("hide");
view.querySelector(".fldHttpsMode").classList.remove("hide");
view.querySelector(".fldEnableUpnp").classList.remove("hide"); view.querySelector(".fldEnableUpnp").classList.remove("hide");
} else { } else {
view.querySelector(".fldExternalAddressFilter").classList.add("hide"); view.querySelector(".fldExternalAddressFilter").classList.add("hide");
view.querySelector(".fldExternalAddressFilterMode").classList.add("hide"); view.querySelector(".fldExternalAddressFilterMode").classList.add("hide");
view.querySelector(".fldPublicPort").classList.add("hide"); view.querySelector(".fldPublicPort").classList.add("hide");
view.querySelector(".fldPublicHttpsPort").classList.add("hide"); view.querySelector(".fldPublicHttpsPort").classList.add("hide");
view.querySelector(".fldCertificatePath").classList.add("hide");
view.querySelector(".fldCertPassword").classList.add("hide");
view.querySelector(".fldHttpsMode").classList.add("hide");
view.querySelector(".fldEnableUpnp").classList.add("hide"); view.querySelector(".fldEnableUpnp").classList.add("hide");
} }
}); });

View file

@ -20,11 +20,55 @@
<input is="emby-input" type="number" id="txtPortNumber" label="${LabelLocalHttpServerPortNumber}" pattern="[0-9]*" required="required" min="1" max="65535" /> <input is="emby-input" type="number" id="txtPortNumber" label="${LabelLocalHttpServerPortNumber}" pattern="[0-9]*" required="required" min="1" max="65535" />
<div class="fieldDescription">${LabelLocalHttpServerPortNumberHelp}</div> <div class="fieldDescription">${LabelLocalHttpServerPortNumberHelp}</div>
</div> </div>
<div class="inputContainer fldBaseUrl">
<input is="emby-input" id="txtBaseUrl" type="text" label="${LabelBaseUrl}" />
<div class="fieldDescription">${LabelBaseUrlHelp}</div>
</div>
<fieldset class='verticalSection verticalSection-extrabottompadding'>
<legend><h3>${HeaderHttpsSettings}</h3></legend>
<div class="checkboxContainer checkboxContainer-withDescription">
<label>
<input type="checkbox" is="emby-checkbox" id="chkEnableHttps" />
<span>${LabelEnableHttps}</span>
</label>
<div class="fieldDescription checkboxFieldDescription">${LabelEnableHttpsHelp}</div>
</div>
<div class="checkboxContainer checkboxContainer-withDescription">
<label>
<input type="checkbox" is="emby-checkbox" id="chkRequireHttps" />
<span>${LabelRequireHttps}</span>
</label>
<div class="fieldDescription checkboxFieldDescription">${LabelRequireHttpsHelp}</div>
</div>
<div class="inputContainer"> <div class="inputContainer">
<input is="emby-input" type="number" id="txtHttpsPort" pattern="[0-9]*" required="required" min="1" max="65535" label="${LabelHttpsPort}" /> <input is="emby-input" type="number" id="txtHttpsPort" pattern="[0-9]*" required="required" min="1" max="65535" label="${LabelHttpsPort}" />
<div class="fieldDescription">${LabelHttpsPortHelp}</div> <div class="fieldDescription">${LabelHttpsPortHelp}</div>
</div> </div>
<div class="inputContainer fldCertificatePath">
<div style="display: flex; align-items: center;">
<div style="flex-grow:1;">
<input is="emby-input" type="text" id="txtCertificatePath" label="${LabelCustomCertificatePath}" autocomplete="off" />
</div>
<button type="button" is="paper-icon-button-light" id="btnSelectCertPath" title="${ButtonSelectDirectory}" class="emby-input-iconbutton"><i class="material-icons">search</i></button>
</div>
<div class="fieldDescription">${LabelCustomCertificatePathHelp}</div>
</div>
<div class="inputContainer fldCertPassword">
<input is="emby-input" id="txtCertPassword" type="password" label="${LabelCertificatePassword}" autocomplete="new-password" />
<div class="fieldDescription">${LabelCertificatePasswordHelp}</div>
</div>
</fieldset>
<fieldset class='verticalSection verticalSection-extrabottompadding'>
<legend><h3>${HeaderRemoteAccessSettings}</h3></legend>
<div class="checkboxContainer checkboxContainer-withDescription"> <div class="checkboxContainer checkboxContainer-withDescription">
<label> <label>
<input type="checkbox" is="emby-checkbox" id="chkRemoteAccess" /> <input type="checkbox" is="emby-checkbox" id="chkRemoteAccess" />
@ -42,43 +86,6 @@
<option value="blacklist">${Blacklist}</option> <option value="blacklist">${Blacklist}</option>
</select> </select>
</div> </div>
<div class="inputContainer fldPublicPort hide">
<input is="emby-input" type="number" label="${LabelPublicHttpPort}" id="txtPublicPort" pattern="[0-9]*" required="required" min="1" max="65535" />
<div class="fieldDescription">${LabelPublicHttpPortHelp}</div>
</div>
<div class="inputContainer fldPublicHttpsPort hide">
<input is="emby-input" type="number" id="txtPublicHttpsPort" pattern="[0-9]*" required="required" min="1" max="65535" label="${LabelPublicHttpsPort}" />
<div class="fieldDescription">${LabelPublicHttpsPortHelp}</div>
</div>
<div class="inputContainer fldBaseUrl">
<input is="emby-input" id="txtBaseUrl" type="text" label="${LabelBaseUrl}" />
<div class="fieldDescription">${LabelBaseUrlHelp}</div>
</div>
<div class="inputContainer fldCertificatePath hide">
<div style="display: flex; align-items: center;">
<div style="flex-grow:1;">
<input is="emby-input" type="text" id="txtCertificatePath" label="${LabelCustomCertificatePath}" autocomplete="off" />
</div>
<button type="button" is="paper-icon-button-light" id="btnSelectCertPath" title="${ButtonSelectDirectory}" class="emby-input-iconbutton"><i class="material-icons">search</i></button>
</div>
<div class="fieldDescription">${LabelCustomCertificatePathHelp}</div>
</div>
<div class="inputContainer fldCertPassword hide">
<input is="emby-input" id="txtCertPassword" type="password" label="${LabelCertificatePassword}" autocomplete="new-password" />
<div class="fieldDescription">${LabelCertificatePasswordHelp}</div>
</div>
<div class="selectContainer fldHttpsMode hide">
<select is="emby-select" id="selectHttpsMode" label="${LabelSecureConnectionsMode}">
<option value="disabled">${Disabled}</option>
<option value="enabled">${PreferredNotRequired}</option>
<option value="required">${RequiredForAllRemoteConnections}</option>
<option value="proxy">${HandledByProxy}</option>
</select>
</div>
<div class="checkboxContainer checkboxContainer-withDescription fldEnableUpnp hide"> <div class="checkboxContainer checkboxContainer-withDescription fldEnableUpnp hide">
<label> <label>
@ -87,6 +94,15 @@
</label> </label>
<div class="fieldDescription checkboxFieldDescription">${LabelEnableAutomaticPortMapHelp}</div> <div class="fieldDescription checkboxFieldDescription">${LabelEnableAutomaticPortMapHelp}</div>
</div> </div>
<div class="inputContainer fldPublicPort hide">
<input is="emby-input" type="number" label="${LabelPublicHttpPort}" id="txtPublicPort" pattern="[0-9]*" required="required" min="1" max="65535" />
<div class="fieldDescription">${LabelPublicHttpPortHelp}</div>
</div>
<div class="inputContainer fldPublicHttpsPort hide">
<input is="emby-input" type="number" id="txtPublicHttpsPort" pattern="[0-9]*" required="required" min="1" max="65535" label="${LabelPublicHttpsPort}" />
<div class="fieldDescription">${LabelPublicHttpsPortHelp}</div>
</div>
</fieldset>
</div> </div>
<div> <div>
<button is="emby-button" type="submit" class="raised button-submit block"> <button is="emby-button" type="submit" class="raised button-submit block">

View file

@ -288,7 +288,6 @@
"H264CrfHelp": "The Constant Rate Factor (CRF) is the default quality setting for the x264 encoder. You can set the values between 0 and 51, where lower values would result in better quality (at the expense of higher file sizes). Sane values are between 18 and 28. The default for x264 is 23, so you can use this as a starting point.", "H264CrfHelp": "The Constant Rate Factor (CRF) is the default quality setting for the x264 encoder. You can set the values between 0 and 51, where lower values would result in better quality (at the expense of higher file sizes). Sane values are between 18 and 28. The default for x264 is 23, so you can use this as a starting point.",
"EncoderPresetHelp": "Choose a faster value to improve performance, or a slower value to improve quality.", "EncoderPresetHelp": "Choose a faster value to improve performance, or a slower value to improve quality.",
"HDPrograms": "HD programs", "HDPrograms": "HD programs",
"HandledByProxy": "Handled by reverse proxy",
"HardwareAccelerationWarning": "Enabling hardware acceleration may cause instability in some environments. Ensure that your operating system and video drivers are fully up to date. If you have difficulty playing video after enabling this, you'll need to change the setting back to None.", "HardwareAccelerationWarning": "Enabling hardware acceleration may cause instability in some environments. Ensure that your operating system and video drivers are fully up to date. If you have difficulty playing video after enabling this, you'll need to change the setting back to None.",
"HeaderAccessSchedule": "Access Schedule", "HeaderAccessSchedule": "Access Schedule",
"HeaderAccessScheduleHelp": "Create an access schedule to limit access to certain hours.", "HeaderAccessScheduleHelp": "Create an access schedule to limit access to certain hours.",
@ -380,6 +379,7 @@
"HeaderGuideProviders": "TV Guide Data Providers", "HeaderGuideProviders": "TV Guide Data Providers",
"HeaderHome": "Home", "HeaderHome": "Home",
"HeaderHttpHeaders": "HTTP Headers", "HeaderHttpHeaders": "HTTP Headers",
"HeaderHttpsSettings": "HTTPS Settings",
"HeaderIdentification": "Identification", "HeaderIdentification": "Identification",
"HeaderIdentificationCriteriaHelp": "Enter at least one identification criteria.", "HeaderIdentificationCriteriaHelp": "Enter at least one identification criteria.",
"HeaderIdentificationHeader": "Identification Header", "HeaderIdentificationHeader": "Identification Header",
@ -446,6 +446,7 @@
"HeaderRecentlyPlayed": "Recently Played", "HeaderRecentlyPlayed": "Recently Played",
"HeaderRecordingOptions": "Recording Options", "HeaderRecordingOptions": "Recording Options",
"HeaderRecordingPostProcessing": "Recording Post Processing", "HeaderRecordingPostProcessing": "Recording Post Processing",
"HeaderRemoteAccessSettings": "Remote Access Settings",
"HeaderRemoteControl": "Remote Control", "HeaderRemoteControl": "Remote Control",
"HeaderRemoveMediaFolder": "Remove Media Folder", "HeaderRemoveMediaFolder": "Remove Media Folder",
"HeaderRemoveMediaLocation": "Remove Media Location", "HeaderRemoveMediaLocation": "Remove Media Location",
@ -626,7 +627,7 @@
"LabelEmbedAlbumArtDidl": "Embed album art in Didl", "LabelEmbedAlbumArtDidl": "Embed album art in Didl",
"LabelEmbedAlbumArtDidlHelp": "Some devices prefer this method for obtaining album art. Others may fail to play with this option enabled.", "LabelEmbedAlbumArtDidlHelp": "Some devices prefer this method for obtaining album art. Others may fail to play with this option enabled.",
"LabelEnableAutomaticPortMap": "Enable automatic port mapping", "LabelEnableAutomaticPortMap": "Enable automatic port mapping",
"LabelEnableAutomaticPortMapHelp": "Attempt to automatically map the public port to the local port via UPnP. This may not work with some router models. Changes will not apply until after a server restart.", "LabelEnableAutomaticPortMapHelp": "Attempt to automatically map the public ports to local ports via UPnP. This may not work with some router models. Changes will not apply until after a server restart.",
"LabelEnableBlastAliveMessages": "Blast alive messages", "LabelEnableBlastAliveMessages": "Blast alive messages",
"LabelEnableBlastAliveMessagesHelp": "Enable this if the server is not detected reliably by other UPnP devices on your network.", "LabelEnableBlastAliveMessagesHelp": "Enable this if the server is not detected reliably by other UPnP devices on your network.",
"LabelEnableDlnaClientDiscoveryInterval": "Client discovery interval (seconds)", "LabelEnableDlnaClientDiscoveryInterval": "Client discovery interval (seconds)",
@ -638,6 +639,8 @@
"LabelEnableDlnaServer": "Enable DLNA server", "LabelEnableDlnaServer": "Enable DLNA server",
"LabelEnableDlnaServerHelp": "Allows UPnP devices on your network to browse and play content.", "LabelEnableDlnaServerHelp": "Allows UPnP devices on your network to browse and play content.",
"LabelEnableHardwareDecodingFor": "Enable hardware decoding for:", "LabelEnableHardwareDecodingFor": "Enable hardware decoding for:",
"LabelEnableHttps": "Enable HTTPS",
"LabelEnableHttpsHelp": "Enables the server to listen on the configured HTTPS post. A valid certificate must also be configured in order for this to take effect.",
"LabelEnableRealtimeMonitor": "Enable real time monitoring", "LabelEnableRealtimeMonitor": "Enable real time monitoring",
"LabelEnableRealtimeMonitorHelp": "Changes to files will be processed immediately, on supported file systems.", "LabelEnableRealtimeMonitorHelp": "Changes to files will be processed immediately, on supported file systems.",
"LabelEnableSingleImageInDidlLimit": "Limit to single embedded image", "LabelEnableSingleImageInDidlLimit": "Limit to single embedded image",
@ -803,6 +806,8 @@
"LabelReleaseDate": "Release date:", "LabelReleaseDate": "Release date:",
"LabelRemoteClientBitrateLimit": "Internet streaming bitrate limit (Mbps):", "LabelRemoteClientBitrateLimit": "Internet streaming bitrate limit (Mbps):",
"LabelRemoteClientBitrateLimitHelp": "An optional per-stream bitrate limit for all out of network devices. This is useful to prevent devices from requesting a higher bitrate than your internet connection can handle. This may result in increased CPU load on your server in order to transcode videos on the fly to a lower bitrate.", "LabelRemoteClientBitrateLimitHelp": "An optional per-stream bitrate limit for all out of network devices. This is useful to prevent devices from requesting a higher bitrate than your internet connection can handle. This may result in increased CPU load on your server in order to transcode videos on the fly to a lower bitrate.",
"LabelRequireHttps": "Require HTTPS",
"LabelRequireHttpsHelp": "If checked, the server will automatically redirect all requests over HTTP to HTTPS. This has no effect if the server is not listening on HTTPS.",
"LabelRuntimeMinutes": "Run time (minutes):", "LabelRuntimeMinutes": "Run time (minutes):",
"LabelSaveLocalMetadata": "Save artwork into media folders", "LabelSaveLocalMetadata": "Save artwork into media folders",
"LabelSaveLocalMetadataHelp": "Saving artwork into media folders will put them in a place where they can be easily edited.", "LabelSaveLocalMetadataHelp": "Saving artwork into media folders will put them in a place where they can be easily edited.",
@ -811,7 +816,6 @@
"EnableFastImageFadeIn": "Fast image fade-in", "EnableFastImageFadeIn": "Fast image fade-in",
"EnableFastImageFadeInHelp": "Enable faster fade-in animation for loaded images", "EnableFastImageFadeInHelp": "Enable faster fade-in animation for loaded images",
"LabelSeasonNumber": "Season number:", "LabelSeasonNumber": "Season number:",
"LabelSecureConnectionsMode": "Secure connection mode:",
"LabelSelectFolderGroups": "Automatically group content from the following folders into views such as Movies, Music and TV:", "LabelSelectFolderGroups": "Automatically group content from the following folders into views such as Movies, Music and TV:",
"LabelSelectFolderGroupsHelp": "Folders that are unchecked will be displayed by themselves in their own view.", "LabelSelectFolderGroupsHelp": "Folders that are unchecked will be displayed by themselves in their own view.",
"LabelSelectUsers": "Select users:", "LabelSelectUsers": "Select users:",
@ -1253,7 +1257,6 @@
"PreferEmbeddedTitlesOverFileNamesHelp": "This determines the default display title when no internet metadata or local metadata is available.", "PreferEmbeddedTitlesOverFileNamesHelp": "This determines the default display title when no internet metadata or local metadata is available.",
"PreferEmbeddedEpisodeInfosOverFileNamesHelp": "This uses the episode information from the embedded metadata if available.", "PreferEmbeddedEpisodeInfosOverFileNamesHelp": "This uses the episode information from the embedded metadata if available.",
"PreferEmbeddedEpisodeInfosOverFileNames": "Prefer embedded episode information over filenames", "PreferEmbeddedEpisodeInfosOverFileNames": "Prefer embedded episode information over filenames",
"PreferredNotRequired": "Preferred, but not required",
"Premiere": "Premiere", "Premiere": "Premiere",
"Premieres": "Premieres", "Premieres": "Premieres",
"Previous": "Previous", "Previous": "Previous",
@ -1292,7 +1295,6 @@
"RepeatOne": "Repeat one", "RepeatOne": "Repeat one",
"ReplaceAllMetadata": "Replace all metadata", "ReplaceAllMetadata": "Replace all metadata",
"ReplaceExistingImages": "Replace existing images", "ReplaceExistingImages": "Replace existing images",
"RequiredForAllRemoteConnections": "Required for all remote connections",
"RestartPleaseWaitMessage": "Please wait while Jellyfin Server shuts down and restarts. This may take a minute or two.", "RestartPleaseWaitMessage": "Please wait while Jellyfin Server shuts down and restarts. This may take a minute or two.",
"ResumeAt": "Resume from {0}", "ResumeAt": "Resume from {0}",
"Rewind": "Rewind", "Rewind": "Rewind",