Added UI for Database settings

Also cleanup some documentation

*Database Settings have been renamed and will require manually fixing
from 6.2beta1*

database.varchar.maxlength -> DatabaseMysqlMaxlength
database.config.type -> DatabaseConfigType
database.config.embed.driver -> DatabasigEmbedDriver
database.config.embed.url -> DatabaseConfigEmbedUrl
database.config.embed.username -> DatabasigEmbedUsername
database.config.embed.password -> DatabasigEmbedPassword
database.config.jndi.name -> DatabaseConfigJNDIName
database.usertable.quote -> DatabaseUsertableQuote

Signed-off-by: Andrew DeMaria <lostonamountain@gmail.com>
master
Andrew DeMaria 8 years ago
parent 9b35781b87
commit 9c224b7853
No known key found for this signature in database
GPG Key ID: 0A3F5E91F8364EDF
  1. 40
      documentation/CONFIGURATION.md
  2. 26
      documentation/DATABASE.md
  3. 6
      libresonic-main/pom.xml
  4. 82
      libresonic-main/src/main/java/org/libresonic/player/command/DatabaseSettingsCommand.java
  5. 106
      libresonic-main/src/main/java/org/libresonic/player/controller/DatabaseSettingsController.java
  6. 2
      libresonic-main/src/main/java/org/libresonic/player/security/WebSecurityConfig.java
  7. 102
      libresonic-main/src/main/java/org/libresonic/player/service/SettingsService.java
  8. 2
      libresonic-main/src/main/java/org/libresonic/player/spring/LibresonicPropertySourceConfigurer.java
  9. 93
      libresonic-main/src/main/java/org/libresonic/player/util/Util.java
  10. 8
      libresonic-main/src/main/resources/applicationContext-db-embed.xml
  11. 2
      libresonic-main/src/main/resources/applicationContext-db-jndi.xml
  12. 4
      libresonic-main/src/main/resources/applicationContext-db.xml
  13. 2
      libresonic-main/src/main/resources/liquibase/db-changelog.xml
  14. 33
      libresonic-main/src/main/resources/org/libresonic/player/i18n/ResourceBundle_en.properties
  15. 128
      libresonic-main/src/main/webapp/WEB-INF/jsp/databaseSettings.jsp
  16. 0
      libresonic-main/src/main/webapp/WEB-INF/jsp/generalDatabaseSettings.jsp
  17. 2
      libresonic-main/src/main/webapp/WEB-INF/jsp/settingsHeader.jsp

@ -0,0 +1,40 @@
# Startup Configuration Guide
Libresonic has some system-wide configuration. These configurations are stored in the
`libresonic.properties` file. There is one exception, which is the `libresonic.home` parameter which
is supplied as a Java System Property.
## `libresonic.properties`
These parameters are simple key-value pairs stored in a list. It is recommended that these parameters
are changed through the web interface settings page. However, they can also be modified directly. Shutdown
your server first, modify, then start it for changes to take effect.
## Java Parameters
The `libresonic.home` parameter is a Java System Property that is not modifiable through the web interface.
It must be configured via Java startup parameters. See below for steps to do this.
#### `libresonic.home`
This parameter dictates the folder where Libresonic will store its logs,
settings, transcode binaries, index and database if using the default H2
database. As such it is recommended to backup this folder.
*default: `/var/libresonic` or `C:\\music`*
#### Setting Java Parameters on Tomcat
As described in the [RUNNING.txt](http://tomcat.apache.org/tomcat-8.0-doc/RUNNING.txt) doc provided by tomcat,
you can create a file named `setenv.sh` or for windows `setenv.bat` in the Tomcat home `bin` folder to modify the
java args.
Here is an example of a `setenv.sh` file (`setenv.bat` has slightly different syntax):
```
export JAVA_OPTS="$JAVA_OPTS -Dlibresonic.home=/home/andrew/.cache/libresonic-test"
```
#### Setting Java Parameters for Standalone Package (SpringBoot)
When running the standalone package, add `-Dlibresonic.home=YOUR_PATH_HERE` to the `java` command line right before the
`-jar` argument. Here is an example for linux (windows users will want to use their OS specific path syntax i.e.
`C:\\your\path`)
```
java -Dlibresonic.home=/home/andrew/libresonichome -jar libresonic.war
```

@ -21,16 +21,19 @@ We will refer to container managed configuration as jndi and libresonic managed
In your libresonic.properties file, you will need to add the following settings (this is just an example): In your libresonic.properties file, you will need to add the following settings (this is just an example):
``` ```
database.config.type=embed DatabaseConfigType=embed
database.config.embed.driver=org.hsqldb.jdbcDriver DatabaseConfigEmbedDriver=org.hsqldb.jdbcDriver
database.config.embed.url=jdbc:hsqldb:file:/tmp/libre/db/libresonic DatabaseConfigEmbedUrl=jdbc:hsqldb:file:/tmp/libre/db/libresonic
database.config.embed.username=sa DatabaseConfigEmbedUsername=sa
database.config.embed.password= DatabaseConfigEmbedPassword=
``` ```
In addition, you will need to ensure that a jdbc driver suitable for your In addition, you will need to ensure that a jdbc driver suitable for your
database is on the database is on the
[classpath](https://docs.oracle.com/javase/8/docs/technotes/tools/windows/classpath.html) [classpath](https://docs.oracle.com/javase/8/docs/technotes/tools/windows/classpath.html).
*Note adding to the classpath is currently pretty difficult for spring-boot. Tomcat is easy, just copy into tomcat home
/lib. TODO: provide prebuilt artifacts with tested databases built in?*
## JNDI ## JNDI
*Before doing anything, make sure your database is properly backed up. Ensure your server is shutdown* *Before doing anything, make sure your database is properly backed up. Ensure your server is shutdown*
@ -38,8 +41,8 @@ database is on the
In your libresonic.properties file, you will need to add the following settings (this is just an example): In your libresonic.properties file, you will need to add the following settings (this is just an example):
``` ```
database.config.type=jndi DatabaseConfigType=jndi
database.config.jndi.name=jdbc/libresonicDB DatabaseConfigJNDIName=jdbc/libresonicDB
``` ```
Then in your context.xml in your tomcat directory, add the jndi config: Then in your context.xml in your tomcat directory, add the jndi config:
@ -65,5 +68,10 @@ Finally, copy the jdbc driver from the database vendor website to the `lib` dire
`stringtype=unspecified` on your jdbc url string is necessary. `stringtype=unspecified` on your jdbc url string is necessary.
You will also need to add `database.usertable.quote=\"` to your properties You will also need to add `DatabaseUsertableQuote=\"` to your properties
file. This is due to the fact that our `user` table is a keyword for postgres. file. This is due to the fact that our `user` table is a keyword for postgres.
## Troubleshooting
In the event that you change these settings, restart your server and it fails to start, you can remedy this by reverting
to the LEGACY config by removing all `Database*` settings from your `libresonic.properties` file.

@ -381,6 +381,12 @@
<artifactId>maven-artifact</artifactId> <artifactId>maven-artifact</artifactId>
<version>3.3.9</version> <version>3.3.9</version>
</dependency> </dependency>
<dependency>
<groupId>javax.validation</groupId>
<artifactId>validation-api</artifactId>
<version>1.1.0.Final</version>
</dependency>
</dependencies> </dependencies>
<build> <build>

@ -0,0 +1,82 @@
package org.libresonic.player.command;
import org.libresonic.player.spring.DataSourceConfigType;
import javax.validation.constraints.NotNull;
public class DatabaseSettingsCommand {
@NotNull
private DataSourceConfigType configType;
private String embedDriver;
private String embedPassword;
private String embedUrl;
private String embedUsername;
private String JNDIName;
private int mysqlVarcharMaxlength;
private String usertableQuote;
public DataSourceConfigType getConfigType() {
return configType;
}
public void setConfigType(DataSourceConfigType configType) {
this.configType = configType;
}
public String getEmbedDriver() {
return embedDriver;
}
public void setEmbedDriver(String embedDriver) {
this.embedDriver = embedDriver;
}
public String getEmbedPassword() {
return embedPassword;
}
public void setEmbedPassword(String embedPassword) {
this.embedPassword = embedPassword;
}
public String getEmbedUrl() {
return embedUrl;
}
public void setEmbedUrl(String embedUrl) {
this.embedUrl = embedUrl;
}
public String getEmbedUsername() {
return embedUsername;
}
public void setEmbedUsername(String embedUsername) {
this.embedUsername = embedUsername;
}
public String getJNDIName() {
return JNDIName;
}
public void setJNDIName(String JNDIName) {
this.JNDIName = JNDIName;
}
public int getMysqlVarcharMaxlength() {
return mysqlVarcharMaxlength;
}
public void setMysqlVarcharMaxlength(int mysqlVarcharMaxlength) {
this.mysqlVarcharMaxlength = mysqlVarcharMaxlength;
}
public String getUsertableQuote() {
return usertableQuote;
}
public void setUsertableQuote(String usertableQuote) {
this.usertableQuote = usertableQuote;
}
}

@ -0,0 +1,106 @@
/*
This file is part of Libresonic.
Libresonic is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
Libresonic is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Libresonic. If not, see <http://www.gnu.org/licenses/>.
Copyright 2016 (C) Libresonic Authors
Based upon Subsonic, Copyright 2009 (C) Sindre Mehus
*/
package org.libresonic.player.controller;
import org.libresonic.player.command.DatabaseSettingsCommand;
import org.libresonic.player.dao.AlbumDao;
import org.libresonic.player.dao.ArtistDao;
import org.libresonic.player.dao.MediaFileDao;
import org.libresonic.player.service.MediaScannerService;
import org.libresonic.player.service.SettingsService;
import org.libresonic.player.spring.DataSourceConfigType;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.validation.BindingResult;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.servlet.mvc.support.RedirectAttributes;
@Controller
@RequestMapping("/databaseSettings")
public class DatabaseSettingsController {
@Autowired
private SettingsService settingsService;
@Autowired
private MediaScannerService mediaScannerService;
@Autowired
private ArtistDao artistDao;
@Autowired
private AlbumDao albumDao;
@Autowired
private MediaFileDao mediaFileDao;
@RequestMapping(method = RequestMethod.GET)
protected String displayForm() throws Exception {
return "databaseSettings";
}
@ModelAttribute
protected void formBackingObject(Model model) throws Exception {
DatabaseSettingsCommand command = new DatabaseSettingsCommand();
command.setConfigType(settingsService.getDatabaseConfigType());
command.setEmbedDriver(settingsService.getDatabaseConfigEmbedDriver());
command.setEmbedPassword(settingsService.getDatabaseConfigEmbedPassword());
command.setEmbedUrl(settingsService.getDatabaseConfigEmbedUrl());
command.setEmbedUsername(settingsService.getDatabaseConfigEmbedUsername());
command.setJNDIName(settingsService.getDatabaseConfigJNDIName());
command.setMysqlVarcharMaxlength(settingsService.getDatabaseMysqlVarcharMaxlength());
command.setUsertableQuote(settingsService.getDatabaseUsertableQuote());
model.addAttribute("command", command);
}
@RequestMapping(method = RequestMethod.POST)
protected String onSubmit(@ModelAttribute("command") @Validated DatabaseSettingsCommand command,
BindingResult bindingResult,
RedirectAttributes redirectAttributes) throws Exception {
if (!bindingResult.hasErrors()) {
settingsService.resetDatabaseToDefault();
settingsService.setDatabaseConfigType(command.getConfigType());
switch(command.getConfigType()) {
case EMBED:
settingsService.setDatabaseConfigEmbedDriver(command.getEmbedDriver());
settingsService.setDatabaseConfigEmbedPassword(command.getEmbedPassword());
settingsService.setDatabaseConfigEmbedUrl(command.getEmbedUrl());
settingsService.setDatabaseConfigEmbedUsername(command.getEmbedUsername());
break;
case JNDI:
settingsService.setDatabaseConfigJNDIName(command.getJNDIName());
break;
case LEGACY:
default:
break;
}
if(command.getConfigType() != DataSourceConfigType.LEGACY) {
settingsService.setDatabaseMysqlVarcharMaxlength(command.getMysqlVarcharMaxlength());
settingsService.setDatabaseUsertableQuote(command.getUsertableQuote());
}
redirectAttributes.addFlashAttribute("settings_toast", true);
settingsService.save();
return "redirect:databaseSettings.view";
} else {
return "databaseSettings.view";
}
}
}

@ -79,7 +79,7 @@ public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
"/playerSettings.view", "/shareSettings.view","/passwordSettings.view") "/playerSettings.view", "/shareSettings.view","/passwordSettings.view")
.hasRole("SETTINGS") .hasRole("SETTINGS")
.antMatchers("/generalSettings.view","/advancedSettings.view","/userSettings.view", .antMatchers("/generalSettings.view","/advancedSettings.view","/userSettings.view",
"/musicFolderSettings.view") "/musicFolderSettings.view", "/databaseSettings.view")
.hasRole("ADMIN") .hasRole("ADMIN")
.antMatchers("/deletePlaylist.view","/savePlaylist.view") .antMatchers("/deletePlaylist.view","/savePlaylist.view")
.hasRole("PLAYLIST") .hasRole("PLAYLIST")

@ -26,6 +26,7 @@ import org.libresonic.player.dao.InternetRadioDao;
import org.libresonic.player.dao.MusicFolderDao; import org.libresonic.player.dao.MusicFolderDao;
import org.libresonic.player.dao.UserDao; import org.libresonic.player.dao.UserDao;
import org.libresonic.player.domain.*; import org.libresonic.player.domain.*;
import org.libresonic.player.spring.DataSourceConfigType;
import org.libresonic.player.util.FileUtil; import org.libresonic.player.util.FileUtil;
import org.libresonic.player.util.StringUtil; import org.libresonic.player.util.StringUtil;
import org.libresonic.player.util.Util; import org.libresonic.player.util.Util;
@ -105,6 +106,16 @@ public class SettingsService {
private static final String KEY_SMTP_PASSWORD = "SmtpPassword"; private static final String KEY_SMTP_PASSWORD = "SmtpPassword";
private static final String KEY_SMTP_FROM = "SmtpFrom"; private static final String KEY_SMTP_FROM = "SmtpFrom";
// Database Settings
private static final String KEY_DATABASE_CONFIG_TYPE = "DatabaseConfigType";
private static final String KEY_DATABASE_CONFIG_EMBED_DRIVER = "DatabaseConfigEmbedDriver";
private static final String KEY_DATABASE_CONFIG_EMBED_URL = "DatabaseConfigEmbedUrl";
private static final String KEY_DATABASE_CONFIG_EMBED_USERNAME = "DatabaseConfigEmbedUsername";
private static final String KEY_DATABASE_CONFIG_EMBED_PASSWORD = "DatabaseConfigEmbedPassword";
private static final String KEY_DATABASE_CONFIG_JNDI_NAME = "DatabaseConfigJNDIName";
private static final String KEY_DATABASE_MYSQL_VARCHAR_MAXLENGTH = "DatabaseMysqlMaxlength";
private static final String KEY_DATABASE_USERTABLE_QUOTE = "DatabaseUsertableQuote";
// Default values. // Default values.
private static final String DEFAULT_INDEX_STRING = "A B C D E F G H I J K L M N O P Q R S T U V W X-Z(XYZ)"; private static final String DEFAULT_INDEX_STRING = "A B C D E F G H I J K L M N O P Q R S T U V W X-Z(XYZ)";
private static final String DEFAULT_IGNORED_ARTICLES = "The El La Los Las Le Les"; private static final String DEFAULT_IGNORED_ARTICLES = "The El La Los Las Le Les";
@ -168,13 +179,26 @@ public class SettingsService {
private static final String DEFAULT_SMTP_PASSWORD = null; private static final String DEFAULT_SMTP_PASSWORD = null;
private static final String DEFAULT_SMTP_FROM = "libresonic@libresonic.org"; private static final String DEFAULT_SMTP_FROM = "libresonic@libresonic.org";
private static final DataSourceConfigType DEFAULT_DATABASE_CONFIG_TYPE = DataSourceConfigType.LEGACY;
private static final String DEFAULT_DATABASE_CONFIG_EMBED_DRIVER = null;
private static final String DEFAULT_DATABASE_CONFIG_EMBED_URL = null;
private static final String DEFAULT_DATABASE_CONFIG_EMBED_USERNAME = null;
private static final String DEFAULT_DATABASE_CONFIG_EMBED_PASSWORD = null;
private static final String DEFAULT_DATABASE_CONFIG_JNDI_NAME = null;
private static final Integer DEFAULT_DATABASE_MYSQL_VARCHAR_MAXLENGTH = 512;
private static final String DEFAULT_DATABASE_USERTABLE_QUOTE = null;
// Array of obsolete keys. Used to clean property file. // Array of obsolete keys. Used to clean property file.
private static final List<String> OBSOLETE_KEYS = Arrays.asList("PortForwardingPublicPort", "PortForwardingLocalPort", private static final List<String> OBSOLETE_KEYS = Arrays.asList("PortForwardingPublicPort", "PortForwardingLocalPort",
"DownsamplingCommand", "DownsamplingCommand2", "DownsamplingCommand3", "AutoCoverBatch", "MusicMask", "DownsamplingCommand", "DownsamplingCommand2", "DownsamplingCommand3", "AutoCoverBatch", "MusicMask",
"VideoMask", "CoverArtMask, HlsCommand", "HlsCommand2", "JukeboxCommand", "VideoMask", "CoverArtMask, HlsCommand", "HlsCommand2", "JukeboxCommand",
"CoverArtFileTypes", "UrlRedirectCustomHost", "CoverArtLimit", "StreamPort", "CoverArtFileTypes", "UrlRedirectCustomHost", "CoverArtLimit", "StreamPort",
"PortForwardingEnabled", "RewriteUrl", "UrlRedirectCustomUrl", "UrlRedirectContextPath", "PortForwardingEnabled", "RewriteUrl", "UrlRedirectCustomUrl", "UrlRedirectContextPath",
"UrlRedirectFrom", "UrlRedirectionEnabled", "UrlRedirectType", "Port", "HttpsPort"); "UrlRedirectFrom", "UrlRedirectionEnabled", "UrlRedirectType", "Port", "HttpsPort",
// Database settings renamed
"database.varchar.maxlength", "database.config.type", "database.config.embed.driver",
"database.config.embed.url", "database.config.embed.username", "database.config.embed.password",
"database.config.jndi.name", "database.usertable.quote");
private static final String LOCALES_FILE = "/org/libresonic/player/i18n/locales.txt"; private static final String LOCALES_FILE = "/org/libresonic/player/i18n/locales.txt";
private static final String THEMES_FILE = "/org/libresonic/player/theme/themes.txt"; private static final String THEMES_FILE = "/org/libresonic/player/theme/themes.txt";
@ -1243,7 +1267,83 @@ public class SettingsService {
setString(KEY_SMTP_FROM, smtpFrom); setString(KEY_SMTP_FROM, smtpFrom);
} }
public DataSourceConfigType getDatabaseConfigType() {
String raw = getString(KEY_DATABASE_CONFIG_TYPE, DEFAULT_DATABASE_CONFIG_TYPE.name());
return DataSourceConfigType.valueOf(StringUtils.upperCase(raw));
}
public void setDatabaseConfigType(DataSourceConfigType databaseConfigType) {
setString(KEY_DATABASE_CONFIG_TYPE, databaseConfigType.name());
}
public String getDatabaseConfigEmbedDriver() {
return getString(KEY_DATABASE_CONFIG_EMBED_DRIVER, DEFAULT_DATABASE_CONFIG_EMBED_DRIVER);
}
public void setDatabaseConfigEmbedDriver(String embedDriver) {
setString(KEY_DATABASE_CONFIG_EMBED_DRIVER, embedDriver);
}
public String getDatabaseConfigEmbedUrl() {
return getString(KEY_DATABASE_CONFIG_EMBED_URL, DEFAULT_DATABASE_CONFIG_EMBED_URL);
}
public void setDatabaseConfigEmbedUrl(String url) {
setString(KEY_DATABASE_CONFIG_EMBED_URL, url);
}
public String getDatabaseConfigEmbedUsername() {
return getString(KEY_DATABASE_CONFIG_EMBED_USERNAME, DEFAULT_DATABASE_CONFIG_EMBED_USERNAME);
}
public void setDatabaseConfigEmbedUsername(String username) {
setString(KEY_DATABASE_CONFIG_EMBED_USERNAME, username);
}
public String getDatabaseConfigEmbedPassword() {
return getString(KEY_DATABASE_CONFIG_EMBED_PASSWORD, DEFAULT_DATABASE_CONFIG_EMBED_PASSWORD);
}
public void setDatabaseConfigEmbedPassword(String password) {
setString(KEY_DATABASE_CONFIG_EMBED_PASSWORD, password);
}
public String getDatabaseConfigJNDIName() {
return getString(KEY_DATABASE_CONFIG_JNDI_NAME, DEFAULT_DATABASE_CONFIG_JNDI_NAME);
}
public void setDatabaseConfigJNDIName(String jndiName) {
setString(KEY_DATABASE_CONFIG_JNDI_NAME, jndiName);
}
public Integer getDatabaseMysqlVarcharMaxlength() {
return getInt(KEY_DATABASE_MYSQL_VARCHAR_MAXLENGTH, DEFAULT_DATABASE_MYSQL_VARCHAR_MAXLENGTH);
}
public void setDatabaseMysqlVarcharMaxlength(int maxlength) {
setInt(KEY_DATABASE_MYSQL_VARCHAR_MAXLENGTH, maxlength);
}
public String getDatabaseUsertableQuote() {
return getString(KEY_DATABASE_USERTABLE_QUOTE, DEFAULT_DATABASE_USERTABLE_QUOTE);
}
public void setDatabaseUsertableQuote(String usertableQuote) {
setString(KEY_DATABASE_USERTABLE_QUOTE, usertableQuote);
}
public void setConfigurationService(ApacheCommonsConfigurationService configurationService) { public void setConfigurationService(ApacheCommonsConfigurationService configurationService) {
this.configurationService = configurationService; this.configurationService = configurationService;
} }
public void resetDatabaseToDefault() {
setDatabaseConfigEmbedDriver(DEFAULT_DATABASE_CONFIG_EMBED_DRIVER);
setDatabaseConfigEmbedPassword(DEFAULT_DATABASE_CONFIG_EMBED_PASSWORD);
setDatabaseConfigEmbedUrl(DEFAULT_DATABASE_CONFIG_EMBED_URL);
setDatabaseConfigEmbedUsername(DEFAULT_DATABASE_CONFIG_EMBED_USERNAME);
setDatabaseConfigJNDIName(DEFAULT_DATABASE_CONFIG_JNDI_NAME);
setDatabaseMysqlVarcharMaxlength(DEFAULT_DATABASE_MYSQL_VARCHAR_MAXLENGTH);
setDatabaseUsertableQuote(DEFAULT_DATABASE_USERTABLE_QUOTE);
setDatabaseConfigType(DEFAULT_DATABASE_CONFIG_TYPE);
}
} }

@ -13,7 +13,7 @@ import java.util.List;
public class LibresonicPropertySourceConfigurer implements public class LibresonicPropertySourceConfigurer implements
ApplicationContextInitializer<ConfigurableWebApplicationContext> { ApplicationContextInitializer<ConfigurableWebApplicationContext> {
public static final String DATASOURCE_CONFIG_TYPE = "database.config.type"; public static final String DATASOURCE_CONFIG_TYPE = "DatabaseConfigType";
public void initialize(ConfigurableWebApplicationContext ctx) { public void initialize(ConfigurableWebApplicationContext ctx) {

@ -20,14 +20,10 @@
package org.libresonic.player.util; package org.libresonic.player.util;
import org.libresonic.player.Logger; import org.libresonic.player.Logger;
import org.libresonic.player.service.SettingsService;
import javax.servlet.ServletResponse; import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletResponse; import javax.servlet.http.HttpServletResponse;
import java.net.Inet4Address;
import java.net.InetAddress;
import java.net.NetworkInterface;
import java.util.*; import java.util.*;
/** /**
@ -38,7 +34,6 @@ import java.util.*;
public final class Util { public final class Util {
private static final Logger LOG = Logger.getLogger(Util.class); private static final Logger LOG = Logger.getLogger(Util.class);
private static final Random RANDOM = new Random(System.currentTimeMillis());
/** /**
* Disallow external instantiation. * Disallow external instantiation.
@ -65,10 +60,6 @@ public final class Util {
return System.getProperty("os.name", "Windows").toLowerCase().startsWith("windows"); return System.getProperty("os.name", "Windows").toLowerCase().startsWith("windows");
} }
public static boolean isWindowsInstall() {
return "true".equals(System.getProperty("libresonic.windowsInstall"));
}
/** /**
* Similar to {@link ServletResponse#setContentLength(int)}, but this * Similar to {@link ServletResponse#setContentLength(int)}, but this
* method supports lengths bigger than 2GB. * method supports lengths bigger than 2GB.
@ -86,90 +77,6 @@ public final class Util {
} }
} }
/**
* Returns the local IP address. Honours the "libresonic.host" system property.
* <p/>
* NOTE: For improved performance, use {@link SettingsService#getLocalIpAddress()} instead.
*
* @return The local IP, or the loopback address (127.0.0.1) if not found.
*/
public static String getLocalIpAddress() {
List<String> ipAddresses = getLocalIpAddresses();
String libresonicHost = System.getProperty("libresonic.host");
if (libresonicHost != null && ipAddresses.contains(libresonicHost)) {
return libresonicHost;
}
return ipAddresses.get(0);
}
private static List<String> getLocalIpAddresses() {
List<String> result = new ArrayList<String>();
// Try the simple way first.
try {
InetAddress address = InetAddress.getLocalHost();
if (!address.isLoopbackAddress()) {
result.add(address.getHostAddress());
}
} catch (Throwable x) {
LOG.warn("Failed to resolve local IP address.", x);
}
// Iterate through all network interfaces, looking for a suitable IP.
try {
Enumeration<NetworkInterface> interfaces = NetworkInterface.getNetworkInterfaces();
while (interfaces.hasMoreElements()) {
NetworkInterface iface = interfaces.nextElement();
Enumeration<InetAddress> addresses = iface.getInetAddresses();
while (addresses.hasMoreElements()) {
InetAddress addr = addresses.nextElement();
if (addr instanceof Inet4Address && !addr.isLoopbackAddress()) {
result.add(addr.getHostAddress());
}
}
}
} catch (Throwable x) {
LOG.warn("Failed to resolve local IP address.", x);
}
if (result.isEmpty()) {
result.add("127.0.0.1");
}
return result;
}
public static int randomInt(int min, int max) {
if (min >= max) {
return 0;
}
return min + RANDOM.nextInt(max - min);
}
public static <T> Iterable<T> toIterable(final Enumeration<?> e) {
return new Iterable<T>() {
public Iterator<T> iterator() {
return toIterator(e);
}
};
}
public static <T> Iterator<T> toIterator(final Enumeration<?> e) {
return new Iterator<T>() {
public boolean hasNext() {
return e.hasMoreElements();
}
public T next() {
return (T) e.nextElement();
}
public void remove() {
throw new UnsupportedOperationException();
}
};
}
public static <T> List<T> subList(List<T> list, long offset, long max) { public static <T> List<T> subList(List<T> list, long offset, long max) {
return list.subList((int) offset, Math.min(list.size(), (int) (offset + max))); return list.subList((int) offset, Math.min(list.size(), (int) (offset + max)));
} }

@ -6,9 +6,9 @@
<bean id="dataSource" <bean id="dataSource"
class="org.springframework.jdbc.datasource.DriverManagerDataSource"> class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="${database.config.embed.driver}" /> <property name="driverClassName" value="${DatabaseConfigEmbedDriver}" />
<property name="url" value="${database.config.embed.url}" /> <property name="url" value="${DatabaseConfigEmbedUrl}" />
<property name="username" value="${database.config.embed.username}" /> <property name="username" value="${DatabaseConfigEmbedUsername}" />
<property name="password" value="${database.config.embed.password}" /> <property name="password" value="${DatabaseConfigEmbedPassword}" />
</bean> </bean>
</beans> </beans>

@ -7,6 +7,6 @@
http://www.springframework.org/schema/jee http://www.springframework.org/schema/jee/spring-jee.xsd" http://www.springframework.org/schema/jee http://www.springframework.org/schema/jee/spring-jee.xsd"
profile="jndi"> profile="jndi">
<jee:jndi-lookup id="dataSource" <jee:jndi-lookup id="dataSource"
jndi-name="${database.config.jndi.name}" jndi-name="${DatabaseConfigJNDIName}"
expected-type="javax.sql.DataSource" /> expected-type="javax.sql.DataSource" />
</beans> </beans>

@ -23,7 +23,7 @@
</bean> </bean>
<bean id="userTableQuote" class="java.lang.String"> <bean id="userTableQuote" class="java.lang.String">
<constructor-arg value="${database.usertable.quote:}" /> <constructor-arg value="${DatabaseUsertableQuote:}" />
</bean> </bean>
<bean id="liquibase" class="org.libresonic.player.spring.SpringLiquibase"> <bean id="liquibase" class="org.libresonic.player.spring.SpringLiquibase">
@ -33,7 +33,7 @@
<property name="changeLogParameters"> <property name="changeLogParameters">
<map> <map>
<entry key="defaultMusicFolder" value="#{T(org.libresonic.player.util.Util).getDefaultMusicFolder()}" /> <entry key="defaultMusicFolder" value="#{T(org.libresonic.player.util.Util).getDefaultMusicFolder()}" />
<entry key="varcharLimit" value="${database.varchar.maxlength:512}" /> <entry key="mysqlVarcharLimit" value="${DatabaseMysqlMaxlength:512}" />
<entry key="userTableQuote" value-ref="userTableQuote" /> <entry key="userTableQuote" value-ref="userTableQuote" />
</map> </map>
</property> </property>

@ -5,7 +5,7 @@
<property name="binary_type" dbms="hsqldb" value="binary" /> <property name="binary_type" dbms="hsqldb" value="binary" />
<property name="binary_type" value="blob" /> <property name="binary_type" value="blob" />
<property name="curr_date_expr" value="current_timestamp" /> <property name="curr_date_expr" value="current_timestamp" />
<property name="varchar_type" dbms="mysql" value="varchar(${varcharLimit})" /> <property name="varchar_type" dbms="mysql" value="varchar(${mysqlVarcharLimit})" />
<property name="varchar_type" value="varchar" /> <property name="varchar_type" value="varchar" />
<include file="legacy/legacy-changelog.xml" relativeToChangelogFile="true"/> <include file="legacy/legacy-changelog.xml" relativeToChangelogFile="true"/>
<include file="6.2/changelog.xml" relativeToChangelogFile="true"/> <include file="6.2/changelog.xml" relativeToChangelogFile="true"/>

@ -340,6 +340,7 @@ settingsheader.user = Users
settingsheader.search = Search/caching settingsheader.search = Search/caching
settingsheader.coverArt = Cover art settingsheader.coverArt = Cover art
settingsheader.password = Password settingsheader.password = Password
settingsheader.database = Database
# generalSettings.jsp # generalSettings.jsp
generalsettings.playlistfolder = Import playlists from generalsettings.playlistfolder = Import playlists from
@ -599,6 +600,22 @@ usersettings.ldapdisabled = LDAP authentication is not enabled. See Advanced set
usersettings.passwordnotsupportedforldap = Can't set or change password for LDAP-authenticated users. usersettings.passwordnotsupportedforldap = Can't set or change password for LDAP-authenticated users.
usersettings.ok = Password successfully changed for user {0}. usersettings.ok = Password successfully changed for user {0}.
# databaseSettings.jsp
databasesettings.moreinfo = Additional information on database settings can be read at \
<a href="https://github.com/Libresonic/libresonic/blob/develop/documentation/DATABASE.md">DATABASE.md</a> on the \
Libresonic github page.
databasesettings.configtype = Database Connection Source
databasesettings.mysqlvarcharmaxlength = MySQL Varchar Maximum Length
databasesettings.usertablequote = User table Quote
databasesettings.jndiname = Data Source JNDI Lookup Name
databasesettings.jdbclibrary = Please ensure that you have your database driver on your \
<a href="https://docs.oracle.com/javase/8/docs/technotes/tools/windows/classpath.html">Java Classpath</a>
databasesettings.embeddriver = JDBC Driver Java classname
databasesettings.embedurl = JDBC URL
databasesettings.embedusername = JDBC Username
databasesettings.embedpassword = JDBC Password
databasettings.restartRequired = Database settings require a restart to take affect.
# main.jsp # main.jsp
main.up = Up main.up = Up
main.playall = Play all main.playall = Play all
@ -732,6 +749,22 @@ helppopup.transcode.title = Max bitrate
helppopup.transcode.text = <p>If you have constrained bandwidth, you may set an upper limit for the bitrate of the music streams. \ helppopup.transcode.text = <p>If you have constrained bandwidth, you may set an upper limit for the bitrate of the music streams. \
For instance, if your original mp3 files are encoded using 256 Kbps (kilobits per second), setting max bitrate \ For instance, if your original mp3 files are encoded using 256 Kbps (kilobits per second), setting max bitrate \
to 128 will make {0} automatically resample the music from 256 to 128 Kbps.</p> to 128 will make {0} automatically resample the music from 256 to 128 Kbps.</p>
helppopup.databaseConfigType.title = Data Source Config Type
helppopup.databaseConfigType.text = <p>Legacy will default to an embed H2 database which is the backwards compatible \
option. Embedded JDBC will connect to a JDBC database with the provided settings. JNDI will lookup \
a DataSource connection already setup in your application container.</p>
helppopup.mysqlvarcharmaxlength.title = MySQL Varchar Max Length
helppopup.mysqlvarcharmaxlength.text = <p>MySQL has a maximum row length and as such needs varchar columns to be \
bounded. This value entered here will be the maximum column size.</p>
helppopup.usertablequote.title = User Table Quote
helppopup.usertablequote.text = <p>The Libresonic users table is named user. This may be a keyword conflict in some \
databases such as Postgres. So for postgres, you will want to use the double quote character (") here</p>
helppopup.jndiname.title = Data Source JNDI Lookup Name
helppopup.jndiname.text = A JNDI name to lookup a Data Source of type javax.sql.DataSource. This is something that is\
created in your application container (i.e. tomcat).
helppopup.embeddriver.title = JDBC Driver Class
helppopup.embeddriver.text = JDBC Driver dependent class name that implments java.sql.Driver. I.E. for postgres one \
would use org.postgresql.Driver. This class must be present on the classpath.
helppopup.playlistfolder.title = Import playlist from helppopup.playlistfolder.title = Import playlist from
helppopup.playlistfolder.text = <p>Libresonic will regularly import playlists stored in this folder.</p> helppopup.playlistfolder.text = <p>Libresonic will regularly import playlists stored in this folder.</p>
helppopup.musicmask.title = Music files helppopup.musicmask.title = Music files

@ -0,0 +1,128 @@
<%@ page language="java" contentType="text/html; charset=utf-8" pageEncoding="iso-8859-1" %>
<%--@elvariable id="command" type="org.libresonic.player.command.DatabaseSettingsCommand"--%>
<html>
<head>
<%@ include file="head.jsp" %>
<%@ include file="jquery.jsp" %>
<script>
function updateShownOptions() {
$(".hideawayDatabaseOptions").hide();
var value = $('select#configType').val();
var objToShow = $("#" + value + "DatabaseOptions");
if (objToShow.length) {
objToShow.show();
}
if(value != 'LEGACY') {
$("#nonLEGACYDatabaseOptions").show();
}
}
$(document).ready(function () {
updateShownOptions();
$('select#configType').on('change', function () {
updateShownOptions();
});
});
</script>
</head>
<body class="mainframe bgcolor1">
<script type="text/javascript" src="<c:url value="/script/wz_tooltip.js"/>"></script>
<script type="text/javascript" src="<c:url value="/script/tip_balloon.js"/>"></script>
<c:import url="settingsHeader.jsp">
<c:param name="cat" value="database"/>
<c:param name="toast" value="${settings_toast}"/>
</c:import>
<form:form commandName="command" action="databaseSettings.view" method="post">
<p><fmt:message key="databasesettings.moreinfo"/></p>
<table style="white-space:nowrap" class="indent">
<tr>
<td><fmt:message key="databasesettings.configtype"/></td>
<td>
<form:select path="configType" cssStyle="width:12em" id="configType">
<form:option value="LEGACY" label="Legacy"/>
<form:option value="EMBED" label="Embedded JDBC"/>
<form:option value="JNDI" label="JNDI"/>
</form:select>
<c:import url="helpToolTip.jsp"><c:param name="topic" value="databaseConfigType"/></c:import>
</td>
</tr>
</table>
<div id="EMBEDDatabaseOptions" class="hideawayDatabaseOptions">
<table style="white-space:nowrap;" class="indent">
<table style="white-space:nowrap;" class="indent">
<tr>
<td><fmt:message key="databasesettings.embeddriver"/></td>
<td>
<form:input path="embedDriver" size="30"/>
<c:import url="helpToolTip.jsp"><c:param name="topic" value="embeddriver"/></c:import>
</td>
</tr>
<tr>
<td><fmt:message key="databasesettings.embedurl"/></td>
<td>
<form:input path="embedUrl" size="58"/>
</td>
</tr>
<tr>
<td><fmt:message key="databasesettings.embedusername"/></td>
<td>
<form:input path="embedUsername" size="36"/>
</td>
</tr>
<tr>
<td><fmt:message key="databasesettings.embedpassword"/></td>
<td>
<form:input path="embedPassword" size="36"/>
</td>
</tr>
</table>
</table>
</div>
<div id="JNDIDatabaseOptions" class="hideawayDatabaseOptions">
<table style="white-space:nowrap;" class="indent">
<tr>
<td><fmt:message key="databasesettings.jndiname"/></td>
<td>
<form:input path="JNDIName" size="36"/>
<c:import url="helpToolTip.jsp"><c:param name="topic" value="jndiname"/></c:import>
</td>
</tr>
</table>
</div>
<div id="nonLEGACYDatabaseOptions" class="hideawayDatabaseOptions">
<table style="white-space:nowrap" class="indent">
<tr>
<td><fmt:message key="databasesettings.mysqlvarcharmaxlength"/></td>
<td>
<form:input path="mysqlVarcharMaxlength" size="8"/>
<c:import url="helpToolTip.jsp"><c:param name="topic" value="mysqlvarcharmaxlength"/></c:import>
</td>
</tr>
<tr>
<td><fmt:message key="databasesettings.usertablequote"/></td>
<td>
<form:input path="usertableQuote" size="1" htmlEscape="true"/>
<c:import url="helpToolTip.jsp"><c:param name="topic" value="usertablequote"/></c:import>
</td>
</tr>
</table>
<p class="warning"><fmt:message key="databasesettings.jdbclibrary"/></p>
</div>
<p class="warning"><fmt:message key="databasettings.restartRequired"/></p>
<p>
<input type="submit" value="<fmt:message key="common.save"/>" style="margin-right:0.3em">
<input type="button" value="<fmt:message key="common.cancel"/>" onclick="location.href='nowPlaying.view'">
</p>
</form:form>
</body>
</html>

@ -9,7 +9,7 @@
</script> </script>
</c:if> </c:if>
<c:set var="categories" value="${param.restricted ? 'personal password player share' : 'musicFolder general advanced personal user player share dlna sonos transcoding internetRadio podcast'}"/> <c:set var="categories" value="${param.restricted ? 'personal password player share' : 'musicFolder general advanced personal user player share dlna sonos transcoding internetRadio podcast database'}"/>
<h1> <h1>
<img src="<spring:theme code="settingsImage"/>" alt=""/> <img src="<spring:theme code="settingsImage"/>" alt=""/>
<span style="vertical-align: middle"><fmt:message key="settingsheader.title"/></span> <span style="vertical-align: middle"><fmt:message key="settingsheader.title"/></span>

Loading…
Cancel
Save