SHARE
TWEET

Untitled

a guest Sep 24th, 2014 284 Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. /*
  2.  This file is part of Subsonic.
  3.  
  4.  Subsonic is free software: you can redistribute it and/or modify
  5.  it under the terms of the GNU General Public License as published by
  6.  the Free Software Foundation, either version 3 of the License, or
  7.  (at your option) any later version.
  8.  
  9.  Subsonic is distributed in the hope that it will be useful,
  10.  but WITHOUT ANY WARRANTY; without even the implied warranty of
  11.  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  12.  GNU General Public License for more details.
  13.  
  14.  You should have received a copy of the GNU General Public License
  15.  along with Subsonic.  If not, see <http://www.gnu.org/licenses/>.
  16.  
  17.  Copyright 2009 (C) Sindre Mehus
  18.  */
  19. package net.sourceforge.subsonic.service;
  20.  
  21. import java.io.File;
  22. import java.io.FileInputStream;
  23. import java.io.FileOutputStream;
  24. import java.io.IOException;
  25. import java.io.InputStream;
  26. import java.io.OutputStream;
  27. import java.util.ArrayList;
  28. import java.util.Arrays;
  29. import java.util.Date;
  30. import java.util.Iterator;
  31. import java.util.List;
  32. import java.util.Locale;
  33. import java.util.Properties;
  34. import java.util.StringTokenizer;
  35. import java.util.concurrent.Executors;
  36. import java.util.concurrent.ScheduledExecutorService;
  37. import java.util.concurrent.ScheduledFuture;
  38. import java.util.concurrent.TimeUnit;
  39.  
  40. import org.apache.commons.io.IOUtils;
  41. import org.apache.commons.lang.StringUtils;
  42. import org.apache.http.client.HttpClient;
  43. import org.apache.http.client.ResponseHandler;
  44. import org.apache.http.client.methods.HttpGet;
  45. import org.apache.http.impl.client.BasicResponseHandler;
  46. import org.apache.http.impl.client.DefaultHttpClient;
  47. import org.apache.http.params.HttpConnectionParams;
  48.  
  49. import net.sourceforge.subsonic.Logger;
  50. import net.sourceforge.subsonic.dao.AvatarDao;
  51. import net.sourceforge.subsonic.dao.InternetRadioDao;
  52. import net.sourceforge.subsonic.dao.MusicFolderDao;
  53. import net.sourceforge.subsonic.dao.UserDao;
  54. import net.sourceforge.subsonic.domain.Avatar;
  55. import net.sourceforge.subsonic.domain.InternetRadio;
  56. import net.sourceforge.subsonic.domain.LicenseInfo;
  57. import net.sourceforge.subsonic.domain.MediaLibraryStatistics;
  58. import net.sourceforge.subsonic.domain.MusicFolder;
  59. import net.sourceforge.subsonic.domain.Theme;
  60. import net.sourceforge.subsonic.domain.UserSettings;
  61. import net.sourceforge.subsonic.util.FileUtil;
  62. import net.sourceforge.subsonic.util.StringUtil;
  63. import net.sourceforge.subsonic.util.Util;
  64.  
  65. /**
  66.  * Provides persistent storage of application settings and preferences.
  67.  *
  68.  * @author Sindre Mehus
  69.  */
  70. public class SettingsService {
  71.  
  72.     // Subsonic home directory.
  73.     private static final File SUBSONIC_HOME_WINDOWS = new File("c:/subsonic");
  74.     private static final File SUBSONIC_HOME_OTHER = new File("/var/subsonic");
  75.  
  76.     // Number of free trial days.
  77.     public static final long TRIAL_DAYS = 30L;
  78.  
  79.     // Global settings.
  80.     private static final String KEY_INDEX_STRING = "IndexString";
  81.     private static final String KEY_IGNORED_ARTICLES = "IgnoredArticles";
  82.     private static final String KEY_SHORTCUTS = "Shortcuts";
  83.     private static final String KEY_PLAYLIST_FOLDER = "PlaylistFolder";
  84.     private static final String KEY_MUSIC_FILE_TYPES = "MusicFileTypes";
  85.     private static final String KEY_VIDEO_FILE_TYPES = "VideoFileTypes";
  86.     private static final String KEY_COVER_ART_FILE_TYPES = "CoverArtFileTypes";
  87.     private static final String KEY_COVER_ART_LIMIT = "CoverArtLimit";
  88.     private static final String KEY_WELCOME_TITLE = "WelcomeTitle";
  89.     private static final String KEY_WELCOME_SUBTITLE = "WelcomeSubtitle";
  90.     private static final String KEY_WELCOME_MESSAGE = "WelcomeMessage2";
  91.     private static final String KEY_LOGIN_MESSAGE = "LoginMessage";
  92.     private static final String KEY_LOCALE_LANGUAGE = "LocaleLanguage";
  93.     private static final String KEY_LOCALE_COUNTRY = "LocaleCountry";
  94.     private static final String KEY_LOCALE_VARIANT = "LocaleVariant";
  95.     private static final String KEY_THEME_ID = "Theme";
  96.     private static final String KEY_INDEX_CREATION_INTERVAL = "IndexCreationInterval";
  97.     private static final String KEY_INDEX_CREATION_HOUR = "IndexCreationHour";
  98.     private static final String KEY_FAST_CACHE_ENABLED = "FastCacheEnabled";
  99.     private static final String KEY_PODCAST_UPDATE_INTERVAL = "PodcastUpdateInterval";
  100.     private static final String KEY_PODCAST_FOLDER = "PodcastFolder";
  101.     private static final String KEY_PODCAST_EPISODE_RETENTION_COUNT = "PodcastEpisodeRetentionCount";
  102.     private static final String KEY_PODCAST_EPISODE_DOWNLOAD_COUNT = "PodcastEpisodeDownloadCount";
  103.     private static final String KEY_DOWNLOAD_BITRATE_LIMIT = "DownloadBitrateLimit";
  104.     private static final String KEY_UPLOAD_BITRATE_LIMIT = "UploadBitrateLimit";
  105.     private static final String KEY_STREAM_PORT = "StreamPort";
  106.     private static final String KEY_LICENSE_EMAIL = "LicenseEmail";
  107.     private static final String KEY_LICENSE_CODE = "LicenseCode";
  108.     private static final String KEY_LICENSE_DATE = "LicenseDate";
  109.     private static final String KEY_DOWNSAMPLING_COMMAND = "DownsamplingCommand4";
  110.     private static final String KEY_HLS_COMMAND = "HlsCommand3";
  111.     private static final String KEY_JUKEBOX_COMMAND = "JukeboxCommand2";
  112.     private static final String KEY_REWRITE_URL = "RewriteUrl";
  113.     private static final String KEY_LDAP_ENABLED = "LdapEnabled";
  114.     private static final String KEY_LDAP_URL = "LdapUrl";
  115.     private static final String KEY_LDAP_MANAGER_DN = "LdapManagerDn";
  116.     private static final String KEY_LDAP_MANAGER_PASSWORD = "LdapManagerPassword";
  117.     private static final String KEY_LDAP_SEARCH_FILTER = "LdapSearchFilter";
  118.     private static final String KEY_LDAP_AUTO_SHADOWING = "LdapAutoShadowing";
  119.     private static final String KEY_GETTING_STARTED_ENABLED = "GettingStartedEnabled";
  120.     private static final String KEY_PORT_FORWARDING_ENABLED = "PortForwardingEnabled";
  121.     private static final String KEY_PORT = "Port";
  122.     private static final String KEY_HTTPS_PORT = "HttpsPort";
  123.     private static final String KEY_URL_REDIRECTION_ENABLED = "UrlRedirectionEnabled";
  124.     private static final String KEY_URL_REDIRECT_FROM = "UrlRedirectFrom";
  125.     private static final String KEY_URL_REDIRECT_CONTEXT_PATH = "UrlRedirectContextPath";
  126.     private static final String KEY_SERVER_ID = "ServerId";
  127.     private static final String KEY_SETTINGS_CHANGED = "SettingsChanged";
  128.     private static final String KEY_LAST_SCANNED = "LastScanned";
  129.     private static final String KEY_ORGANIZE_BY_FOLDER_STRUCTURE = "OrganizeByFolderStructure";
  130.     private static final String KEY_SORT_ALBUMS_BY_YEAR = "SortAlbumsByYear";
  131.     private static final String KEY_MEDIA_LIBRARY_STATISTICS = "MediaLibraryStatistics";
  132.     private static final String KEY_TRIAL_EXPIRES = "TrialExpires";
  133.     private static final String KEY_DLNA_ENABLED = "DlnaEnabled";
  134.     private static final String KEY_DLNA_SERVER_NAME = "DlnaServerName";
  135.  
  136.     // Default values.
  137.     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)";
  138.     private static final String DEFAULT_IGNORED_ARTICLES = "The El La Los Las Le Les";
  139.     private static final String DEFAULT_SHORTCUTS = "New Incoming Podcast";
  140.     private static final String DEFAULT_PLAYLIST_FOLDER = Util.getDefaultPlaylistFolder();
  141.     private static final String DEFAULT_MUSIC_FILE_TYPES = "mp3 ogg oga aac m4a flac wav wma aif aiff ape mpc shn";
  142.     private static final String DEFAULT_VIDEO_FILE_TYPES = "flv avi mpg mpeg mp4 m4v mkv mov wmv ogv divx m2ts";
  143.     private static final String DEFAULT_COVER_ART_FILE_TYPES = "cover.jpg folder.jpg jpg jpeg gif png";
  144.     private static final int DEFAULT_COVER_ART_LIMIT = 50;
  145.     private static final String DEFAULT_WELCOME_TITLE = "Welcome to Subsonic!";
  146.     private static final String DEFAULT_WELCOME_SUBTITLE = null;
  147.     private static final String DEFAULT_WELCOME_MESSAGE = "__Welcome to Subsonic!__\n" +
  148.             "\\\\ \\\\\n" +
  149.             "Subsonic is a free, web-based media streamer, providing ubiquitous access to your music. \n" +
  150.             "\\\\ \\\\\n" +
  151.             "Use it to share your music with friends, or to listen to your own music while at work. You can stream to multiple " +
  152.             "players simultaneously, for instance to one player in your kitchen and another in your living room.\n" +
  153.             "\\\\ \\\\\n" +
  154.             "To change or remove this message, log in with administrator rights and go to {link:Settings > General|generalSettings.view}.";
  155.     private static final String DEFAULT_LOGIN_MESSAGE = null;
  156.     private static final String DEFAULT_LOCALE_LANGUAGE = "en";
  157.     private static final String DEFAULT_LOCALE_COUNTRY = "";
  158.     private static final String DEFAULT_LOCALE_VARIANT = "";
  159.     private static final String DEFAULT_THEME_ID = "default";
  160.     private static final int DEFAULT_INDEX_CREATION_INTERVAL = 1;
  161.     private static final int DEFAULT_INDEX_CREATION_HOUR = 3;
  162.     private static final boolean DEFAULT_FAST_CACHE_ENABLED = false;
  163.     private static final int DEFAULT_PODCAST_UPDATE_INTERVAL = 24;
  164.     private static final String DEFAULT_PODCAST_FOLDER = Util.getDefaultPodcastFolder();
  165.     private static final int DEFAULT_PODCAST_EPISODE_RETENTION_COUNT = 10;
  166.     private static final int DEFAULT_PODCAST_EPISODE_DOWNLOAD_COUNT = 1;
  167.     private static final long DEFAULT_DOWNLOAD_BITRATE_LIMIT = 0;
  168.     private static final long DEFAULT_UPLOAD_BITRATE_LIMIT = 0;
  169.     private static final long DEFAULT_STREAM_PORT = 0;
  170.     private static final String DEFAULT_LICENSE_EMAIL = null;
  171.     private static final String DEFAULT_LICENSE_CODE = null;
  172.     private static final String DEFAULT_LICENSE_DATE = null;
  173.     private static final String DEFAULT_DOWNSAMPLING_COMMAND = "ffmpeg -i %s -map 0:0 -b:a %bk -v 0 -f mp3 -";
  174.     private static final String DEFAULT_HLS_COMMAND = "ffmpeg -ss %o -t %d -i %s -async 1 -b:v %bk -s %wx%h -ar 44100 -ac 2 -v 0 -f mpegts -c:v libx264 -preset superfast -c:a libmp3lame -threads 0 -";
  175.     private static final String DEFAULT_JUKEBOX_COMMAND = "ffmpeg -ss %o -i %s -map 0:0 -v 0 -f au -";
  176.     private static final boolean DEFAULT_REWRITE_URL = true;
  177.     private static final boolean DEFAULT_LDAP_ENABLED = false;
  178.     private static final String DEFAULT_LDAP_URL = "ldap://host.domain.com:389/cn=Users,dc=domain,dc=com";
  179.     private static final String DEFAULT_LDAP_MANAGER_DN = null;
  180.     private static final String DEFAULT_LDAP_MANAGER_PASSWORD = null;
  181.     private static final String DEFAULT_LDAP_SEARCH_FILTER = "(sAMAccountName={0})";
  182.     private static final boolean DEFAULT_LDAP_AUTO_SHADOWING = false;
  183.     private static final boolean DEFAULT_PORT_FORWARDING_ENABLED = false;
  184.     private static final boolean DEFAULT_GETTING_STARTED_ENABLED = true;
  185.     private static final int DEFAULT_PORT = 80;
  186.     private static final int DEFAULT_HTTPS_PORT = 0;
  187.     private static final boolean DEFAULT_URL_REDIRECTION_ENABLED = false;
  188.     private static final String DEFAULT_URL_REDIRECT_FROM = "yourname";
  189.     private static final String DEFAULT_URL_REDIRECT_CONTEXT_PATH = null;
  190.     private static final String DEFAULT_SERVER_ID = null;
  191.     private static final long DEFAULT_SETTINGS_CHANGED = 0L;
  192.     private static final boolean DEFAULT_ORGANIZE_BY_FOLDER_STRUCTURE = true;
  193.     private static final boolean DEFAULT_SORT_ALBUMS_BY_YEAR = true;
  194.     private static final String DEFAULT_MEDIA_LIBRARY_STATISTICS = "0 0 0 0 0";
  195.     private static final String DEFAULT_TRIAL_EXPIRES = null;
  196.     private static final boolean DEFAULT_DLNA_ENABLED = true;
  197.     private static final String DEFAULT_DLNA_SERVER_NAME = "Subsonic";
  198.  
  199.     // Array of obsolete keys.  Used to clean property file.
  200.     private static final List<String> OBSOLETE_KEYS = Arrays.asList("PortForwardingPublicPort", "PortForwardingLocalPort",
  201.             "DownsamplingCommand", "DownsamplingCommand2", "DownsamplingCommand3", "AutoCoverBatch", "MusicMask",
  202.             "VideoMask", "CoverArtMask, HlsCommand", "HlsCommand2", "JukeboxCommand", "UrlRedirectTrialExpires", "VideoTrialExpires");
  203.  
  204.     private static final String LOCALES_FILE = "/net/sourceforge/subsonic/i18n/locales.txt";
  205.     private static final String THEMES_FILE = "/net/sourceforge/subsonic/theme/themes.txt";
  206.  
  207.     private static final Logger LOG = Logger.getLogger(SettingsService.class);
  208.  
  209.     private Properties properties = new Properties();
  210.     private List<Theme> themes;
  211.     private List<Locale> locales;
  212.     private InternetRadioDao internetRadioDao;
  213.     private MusicFolderDao musicFolderDao;
  214.     private UserDao userDao;
  215.     private AvatarDao avatarDao;
  216.     private VersionService versionService;
  217.  
  218.     private String[] cachedCoverArtFileTypesArray;
  219.     private String[] cachedMusicFileTypesArray;
  220.     private String[] cachedVideoFileTypesArray;
  221.     private List<MusicFolder> cachedMusicFolders;
  222.    
  223.     private static File subsonicHome;
  224.  
  225.     private boolean licenseValidated = true;
  226.     private Date licenseExpires;
  227.     private final ScheduledExecutorService executor = Executors.newSingleThreadScheduledExecutor();
  228.     private ScheduledFuture<?> licenseValidationFuture;
  229.  
  230.     private static final long LICENSE_VALIDATION_DELAY_HOURS = 12;
  231.     private static final long LOCAL_IP_LOOKUP_DELAY_SECONDS = 60;
  232.     private String localIpAddress;
  233.  
  234.     public SettingsService() {
  235.         File propertyFile = getPropertyFile();
  236.  
  237.         if (propertyFile.exists()) {
  238.             FileInputStream in = null;
  239.             try {
  240.                 in = new FileInputStream(propertyFile);
  241.                 properties.load(in);
  242.             } catch (Exception x) {
  243.                 LOG.error("Unable to read from property file.", x);
  244.             } finally {
  245.                 IOUtils.closeQuietly(in);
  246.             }
  247.  
  248.             // Remove obsolete properties.
  249.             for (Iterator<Object> iterator = properties.keySet().iterator(); iterator.hasNext();) {
  250.                 String key = (String) iterator.next();
  251.                 if (OBSOLETE_KEYS.contains(key)) {
  252.                     LOG.debug("Removing obsolete property [" + key + ']');
  253.                     iterator.remove();
  254.                 }
  255.             }
  256.         }
  257.  
  258.         // Start trial.
  259.         if (getTrialExpires() == null) {
  260.             Date expiryDate = new Date(System.currentTimeMillis() + TRIAL_DAYS * 24L * 3600L * 1000L);
  261.             setTrialExpires(expiryDate);
  262.         }
  263.  
  264.         save(false);
  265.     }
  266.  
  267.     /**
  268.      * Register in service locator so that non-Spring objects can access me.
  269.      * This method is invoked automatically by Spring.
  270.      */
  271.     public void init() {
  272.         ServiceLocator.setSettingsService(this);
  273.         scheduleLocalIpAddressLookup();
  274.         scheduleLicenseValidation();
  275.     }
  276.  
  277.     public void save() {
  278.         save(true);
  279.     }
  280.  
  281.     public void save(boolean updateChangedDate) {
  282.         if (updateChangedDate) {
  283.             setProperty(KEY_SETTINGS_CHANGED, String.valueOf(System.currentTimeMillis()));
  284.         }
  285.  
  286.         OutputStream out = null;
  287.         try {
  288.             out = new FileOutputStream(getPropertyFile());
  289.             properties.store(out, "Subsonic preferences.  NOTE: This file is automatically generated.");
  290.         } catch (Exception x) {
  291.             LOG.error("Unable to write to property file.", x);
  292.         } finally {
  293.             IOUtils.closeQuietly(out);
  294.         }
  295.     }
  296.  
  297.     private File getPropertyFile() {
  298.         return new File(getSubsonicHome(), "subsonic.properties");
  299.     }
  300.  
  301.     /**
  302.      * Returns the Subsonic home directory.
  303.      *
  304.      * @return The Subsonic home directory, if it exists.
  305.      * @throws RuntimeException If directory doesn't exist.
  306.      */
  307.     public static synchronized File getSubsonicHome() {
  308.  
  309.         if (subsonicHome != null) {
  310.             return subsonicHome;
  311.         }
  312.  
  313.         File home;
  314.  
  315.         String overrideHome = System.getProperty("subsonic.home");
  316.         if (overrideHome != null) {
  317.             home = new File(overrideHome);
  318.         } else {
  319.             boolean isWindows = System.getProperty("os.name", "Windows").toLowerCase().startsWith("windows");
  320.             home = isWindows ? SUBSONIC_HOME_WINDOWS : SUBSONIC_HOME_OTHER;
  321.         }
  322.  
  323.         // Attempt to create home directory if it doesn't exist.
  324.         if (!home.exists() || !home.isDirectory()) {
  325.             boolean success = home.mkdirs();
  326.             if (success) {
  327.                 subsonicHome = home;
  328.             } else {
  329.                 String message = "The directory " + home + " does not exist. Please create it and make it writable. " +
  330.                         "(You can override the directory location by specifying -Dsubsonic.home=... when " +
  331.                         "starting the servlet container.)";
  332.                 System.err.println("ERROR: " + message);
  333.             }
  334.         } else {
  335.             subsonicHome = home;
  336.         }
  337.  
  338.         return home;
  339.     }
  340.  
  341.     private boolean getBoolean(String key, boolean defaultValue) {
  342.         return Boolean.valueOf(properties.getProperty(key, String.valueOf(defaultValue)));
  343.     }
  344.  
  345.     private void setBoolean(String key, boolean value) {
  346.         setProperty(key, String.valueOf(value));
  347.     }
  348.  
  349.     private String getString(String key, String defaultValue) {
  350.         return properties.getProperty(key, defaultValue);
  351.     }
  352.  
  353.     private void setString(String key, String value) {
  354.         setProperty(key, value);
  355.     }
  356.  
  357.     public String getIndexString() {
  358.         return properties.getProperty(KEY_INDEX_STRING, DEFAULT_INDEX_STRING);
  359.     }
  360.  
  361.     public void setIndexString(String indexString) {
  362.         setProperty(KEY_INDEX_STRING, indexString);
  363.     }
  364.  
  365.     public String getIgnoredArticles() {
  366.         return properties.getProperty(KEY_IGNORED_ARTICLES, DEFAULT_IGNORED_ARTICLES);
  367.     }
  368.  
  369.     public String[] getIgnoredArticlesAsArray() {
  370.         return getIgnoredArticles().split("\\s+");
  371.     }
  372.  
  373.     public void setIgnoredArticles(String ignoredArticles) {
  374.         setProperty(KEY_IGNORED_ARTICLES, ignoredArticles);
  375.     }
  376.  
  377.     public String getShortcuts() {
  378.         return properties.getProperty(KEY_SHORTCUTS, DEFAULT_SHORTCUTS);
  379.     }
  380.  
  381.     public String[] getShortcutsAsArray() {
  382.         return StringUtil.split(getShortcuts());
  383.     }
  384.  
  385.     public void setShortcuts(String shortcuts) {
  386.         setProperty(KEY_SHORTCUTS, shortcuts);
  387.     }
  388.  
  389.     public String getPlaylistFolder() {
  390.         return properties.getProperty(KEY_PLAYLIST_FOLDER, DEFAULT_PLAYLIST_FOLDER);
  391.     }
  392.  
  393.     public void setPlaylistFolder(String playlistFolder) {
  394.         setProperty(KEY_PLAYLIST_FOLDER, playlistFolder);
  395.     }
  396.  
  397.     public String getMusicFileTypes() {
  398.         return properties.getProperty(KEY_MUSIC_FILE_TYPES, DEFAULT_MUSIC_FILE_TYPES);
  399.     }
  400.  
  401.     public synchronized void setMusicFileTypes(String fileTypes) {
  402.         setProperty(KEY_MUSIC_FILE_TYPES, fileTypes);
  403.         cachedMusicFileTypesArray = null;
  404.     }
  405.  
  406.     public synchronized String[] getMusicFileTypesAsArray() {
  407.         if (cachedMusicFileTypesArray == null) {
  408.             cachedMusicFileTypesArray = toStringArray(getMusicFileTypes());
  409.         }
  410.         return cachedMusicFileTypesArray;
  411.     }
  412.  
  413.     public String getVideoFileTypes() {
  414.         return properties.getProperty(KEY_VIDEO_FILE_TYPES, DEFAULT_VIDEO_FILE_TYPES);
  415.     }
  416.  
  417.     public synchronized void setVideoFileTypes(String fileTypes) {
  418.         setProperty(KEY_VIDEO_FILE_TYPES, fileTypes);
  419.         cachedVideoFileTypesArray = null;
  420.     }
  421.  
  422.     public synchronized String[] getVideoFileTypesAsArray() {
  423.         if (cachedVideoFileTypesArray == null) {
  424.             cachedVideoFileTypesArray = toStringArray(getVideoFileTypes());
  425.         }
  426.         return cachedVideoFileTypesArray;
  427.     }
  428.  
  429.     public String getCoverArtFileTypes() {
  430.         return properties.getProperty(KEY_COVER_ART_FILE_TYPES, DEFAULT_COVER_ART_FILE_TYPES);
  431.     }
  432.  
  433.     public synchronized void setCoverArtFileTypes(String fileTypes) {
  434.         setProperty(KEY_COVER_ART_FILE_TYPES, fileTypes);
  435.         cachedCoverArtFileTypesArray = null;
  436.     }
  437.  
  438.     public synchronized String[] getCoverArtFileTypesAsArray() {
  439.         if (cachedCoverArtFileTypesArray == null) {
  440.             cachedCoverArtFileTypesArray = toStringArray(getCoverArtFileTypes());
  441.         }
  442.         return cachedCoverArtFileTypesArray;
  443.     }
  444.  
  445.     public int getCoverArtLimit() {
  446.         return Integer.parseInt(properties.getProperty(KEY_COVER_ART_LIMIT, "" + DEFAULT_COVER_ART_LIMIT));
  447.     }
  448.  
  449.     public void setCoverArtLimit(int limit) {
  450.         setProperty(KEY_COVER_ART_LIMIT, "" + limit);
  451.     }
  452.  
  453.     public String getWelcomeTitle() {
  454.         return StringUtils.trimToNull(properties.getProperty(KEY_WELCOME_TITLE, DEFAULT_WELCOME_TITLE));
  455.     }
  456.  
  457.     public void setWelcomeTitle(String title) {
  458.         setProperty(KEY_WELCOME_TITLE, title);
  459.     }
  460.  
  461.     public String getWelcomeSubtitle() {
  462.         return StringUtils.trimToNull(properties.getProperty(KEY_WELCOME_SUBTITLE, DEFAULT_WELCOME_SUBTITLE));
  463.     }
  464.  
  465.     public void setWelcomeSubtitle(String subtitle) {
  466.         setProperty(KEY_WELCOME_SUBTITLE, subtitle);
  467.     }
  468.  
  469.     public String getWelcomeMessage() {
  470.         return StringUtils.trimToNull(properties.getProperty(KEY_WELCOME_MESSAGE, DEFAULT_WELCOME_MESSAGE));
  471.     }
  472.  
  473.     public void setWelcomeMessage(String message) {
  474.         setProperty(KEY_WELCOME_MESSAGE, message);
  475.     }
  476.  
  477.     public String getLoginMessage() {
  478.         return StringUtils.trimToNull(properties.getProperty(KEY_LOGIN_MESSAGE, DEFAULT_LOGIN_MESSAGE));
  479.     }
  480.  
  481.     public void setLoginMessage(String message) {
  482.         setProperty(KEY_LOGIN_MESSAGE, message);
  483.     }
  484.  
  485.     /**
  486.      * Returns the number of days between automatic index creation, of -1 if automatic index
  487.      * creation is disabled.
  488.      */
  489.     public int getIndexCreationInterval() {
  490.         return Integer.parseInt(properties.getProperty(KEY_INDEX_CREATION_INTERVAL, "" + DEFAULT_INDEX_CREATION_INTERVAL));
  491.     }
  492.  
  493.     /**
  494.      * Sets the number of days between automatic index creation, of -1 if automatic index
  495.      * creation is disabled.
  496.      */
  497.     public void setIndexCreationInterval(int days) {
  498.         setProperty(KEY_INDEX_CREATION_INTERVAL, String.valueOf(days));
  499.     }
  500.  
  501.     /**
  502.      * Returns the hour of day (0 - 23) when automatic index creation should run.
  503.      */
  504.     public int getIndexCreationHour() {
  505.         return Integer.parseInt(properties.getProperty(KEY_INDEX_CREATION_HOUR, String.valueOf(DEFAULT_INDEX_CREATION_HOUR)));
  506.     }
  507.  
  508.     /**
  509.      * Sets the hour of day (0 - 23) when automatic index creation should run.
  510.      */
  511.     public void setIndexCreationHour(int hour) {
  512.         setProperty(KEY_INDEX_CREATION_HOUR, String.valueOf(hour));
  513.     }
  514.  
  515.     public boolean isFastCacheEnabled() {
  516.         return getBoolean(KEY_FAST_CACHE_ENABLED, DEFAULT_FAST_CACHE_ENABLED);
  517.     }
  518.  
  519.     public void setFastCacheEnabled(boolean enabled) {
  520.         setBoolean(KEY_FAST_CACHE_ENABLED, enabled);
  521.     }
  522.  
  523.     /**
  524.      * Returns the number of hours between Podcast updates, of -1 if automatic updates
  525.      * are disabled.
  526.      */
  527.     public int getPodcastUpdateInterval() {
  528.         return Integer.parseInt(properties.getProperty(KEY_PODCAST_UPDATE_INTERVAL, String.valueOf(DEFAULT_PODCAST_UPDATE_INTERVAL)));
  529.     }
  530.  
  531.     /**
  532.      * Sets the number of hours between Podcast updates, of -1 if automatic updates
  533.      * are disabled.
  534.      */
  535.     public void setPodcastUpdateInterval(int hours) {
  536.         setProperty(KEY_PODCAST_UPDATE_INTERVAL, String.valueOf(hours));
  537.     }
  538.  
  539.     /**
  540.      * Returns the number of Podcast episodes to keep (-1 to keep all).
  541.      */
  542.     public int getPodcastEpisodeRetentionCount() {
  543.         return Integer.parseInt(properties.getProperty(KEY_PODCAST_EPISODE_RETENTION_COUNT, String.valueOf(DEFAULT_PODCAST_EPISODE_RETENTION_COUNT)));
  544.     }
  545.  
  546.     /**
  547.      * Sets the number of Podcast episodes to keep (-1 to keep all).
  548.      */
  549.     public void setPodcastEpisodeRetentionCount(int count) {
  550.         setProperty(KEY_PODCAST_EPISODE_RETENTION_COUNT, String.valueOf(count));
  551.     }
  552.  
  553.     /**
  554.      * Returns the number of Podcast episodes to download (-1 to download all).
  555.      */
  556.     public int getPodcastEpisodeDownloadCount() {
  557.         return Integer.parseInt(properties.getProperty(KEY_PODCAST_EPISODE_DOWNLOAD_COUNT, String.valueOf(DEFAULT_PODCAST_EPISODE_DOWNLOAD_COUNT)));
  558.     }
  559.  
  560.     /**
  561.      * Sets the number of Podcast episodes to download (-1 to download all).
  562.      */
  563.     public void setPodcastEpisodeDownloadCount(int count) {
  564.         setProperty(KEY_PODCAST_EPISODE_DOWNLOAD_COUNT, String.valueOf(count));
  565.     }
  566.  
  567.     /**
  568.      * Returns the Podcast download folder.
  569.      */
  570.     public String getPodcastFolder() {
  571.         return properties.getProperty(KEY_PODCAST_FOLDER, DEFAULT_PODCAST_FOLDER);
  572.     }
  573.  
  574.     /**
  575.      * Sets the Podcast download folder.
  576.      */
  577.     public void setPodcastFolder(String folder) {
  578.         setProperty(KEY_PODCAST_FOLDER, folder);
  579.     }
  580.  
  581.     /**
  582.      * @return The download bitrate limit in Kbit/s. Zero if unlimited.
  583.      */
  584.     public long getDownloadBitrateLimit() {
  585.         return Long.parseLong(properties.getProperty(KEY_DOWNLOAD_BITRATE_LIMIT, "" + DEFAULT_DOWNLOAD_BITRATE_LIMIT));
  586.     }
  587.  
  588.     /**
  589.      * @param limit The download bitrate limit in Kbit/s. Zero if unlimited.
  590.      */
  591.     public void setDownloadBitrateLimit(long limit) {
  592.         setProperty(KEY_DOWNLOAD_BITRATE_LIMIT, "" + limit);
  593.     }
  594.  
  595.     /**
  596.      * @return The upload bitrate limit in Kbit/s. Zero if unlimited.
  597.      */
  598.     public long getUploadBitrateLimit() {
  599.         return Long.parseLong(properties.getProperty(KEY_UPLOAD_BITRATE_LIMIT, "" + DEFAULT_UPLOAD_BITRATE_LIMIT));
  600.     }
  601.  
  602.     /**
  603.      * @param limit The upload bitrate limit in Kbit/s. Zero if unlimited.
  604.      */
  605.     public void setUploadBitrateLimit(long limit) {
  606.         setProperty(KEY_UPLOAD_BITRATE_LIMIT, "" + limit);
  607.     }
  608.  
  609.     /**
  610.      * @return The non-SSL stream port. Zero if disabled.
  611.      */
  612.     public int getStreamPort() {
  613.         return Integer.parseInt(properties.getProperty(KEY_STREAM_PORT, "" + DEFAULT_STREAM_PORT));
  614.     }
  615.  
  616.     /**
  617.      * @param port The non-SSL stream port. Zero if disabled.
  618.      */
  619.     public void setStreamPort(int port) {
  620.         setProperty(KEY_STREAM_PORT, "" + port);
  621.     }
  622.  
  623.     public String getLicenseEmail() {
  624.         return properties.getProperty(KEY_LICENSE_EMAIL, DEFAULT_LICENSE_EMAIL);
  625.     }
  626.  
  627.     public void setLicenseEmail(String email) {
  628.         setProperty(KEY_LICENSE_EMAIL, email);
  629.     }
  630.  
  631.     public String getLicenseCode() {
  632.         return properties.getProperty(KEY_LICENSE_CODE, DEFAULT_LICENSE_CODE);
  633.     }
  634.  
  635.     public void setLicenseCode(String code) {
  636.         setProperty(KEY_LICENSE_CODE, code);
  637.     }
  638.  
  639.     public Date getLicenseDate() {
  640.         String value = properties.getProperty(KEY_LICENSE_DATE, DEFAULT_LICENSE_DATE);
  641.         return value == null ? null : new Date(Long.parseLong(value));
  642.     }
  643.  
  644.     public void setLicenseDate(Date date) {
  645.         String value = (date == null ? null : String.valueOf(date.getTime()));
  646.         setProperty(KEY_LICENSE_DATE, value);
  647.     }
  648.  
  649.     public boolean isLicenseValid() {
  650.         return true;
  651.     }
  652.  
  653.     public boolean isLicenseValid(String email, String license) {
  654.         return true;
  655.     }
  656.  
  657.     public LicenseInfo getLicenseInfo() {
  658.         Date trialExpires = getTrialExpires();
  659.         Date now = new Date();
  660.         boolean trialValid = trialExpires.after(now);
  661.         long trialDaysLeft = trialValid ? (trialExpires.getTime() - now.getTime()) / (24L * 3600L * 1000L) : 0L;
  662.  
  663.         return new LicenseInfo(getLicenseEmail(), isLicenseValid(), trialExpires, trialDaysLeft, licenseExpires);
  664.     }
  665.  
  666.     public String getDownsamplingCommand() {
  667.         return properties.getProperty(KEY_DOWNSAMPLING_COMMAND, DEFAULT_DOWNSAMPLING_COMMAND);
  668.     }
  669.  
  670.     public void setDownsamplingCommand(String command) {
  671.         setProperty(KEY_DOWNSAMPLING_COMMAND, command);
  672.     }
  673.  
  674.     public String getHlsCommand() {
  675.         return properties.getProperty(KEY_HLS_COMMAND, DEFAULT_HLS_COMMAND);
  676.     }
  677.  
  678.     public void setHlsCommand(String command) {
  679.         setProperty(KEY_HLS_COMMAND, command);
  680.     }
  681.  
  682.     public String getJukeboxCommand() {
  683.         return properties.getProperty(KEY_JUKEBOX_COMMAND, DEFAULT_JUKEBOX_COMMAND);
  684.     }
  685.  
  686.     public boolean isRewriteUrlEnabled() {
  687.         return getBoolean(KEY_REWRITE_URL, DEFAULT_REWRITE_URL);
  688.     }
  689.  
  690.     public void setRewriteUrlEnabled(boolean rewriteUrl) {
  691.         setBoolean(KEY_REWRITE_URL, rewriteUrl);
  692.     }
  693.  
  694.     public boolean isLdapEnabled() {
  695.         return getBoolean(KEY_LDAP_ENABLED, DEFAULT_LDAP_ENABLED);
  696.     }
  697.  
  698.     public void setLdapEnabled(boolean ldapEnabled) {
  699.         setBoolean(KEY_LDAP_ENABLED, ldapEnabled);
  700.     }
  701.  
  702.     public String getLdapUrl() {
  703.         return properties.getProperty(KEY_LDAP_URL, DEFAULT_LDAP_URL);
  704.     }
  705.  
  706.     public void setLdapUrl(String ldapUrl) {
  707.         properties.setProperty(KEY_LDAP_URL, ldapUrl);
  708.     }
  709.  
  710.     public String getLdapSearchFilter() {
  711.         return properties.getProperty(KEY_LDAP_SEARCH_FILTER, DEFAULT_LDAP_SEARCH_FILTER);
  712.     }
  713.  
  714.     public void setLdapSearchFilter(String ldapSearchFilter) {
  715.         properties.setProperty(KEY_LDAP_SEARCH_FILTER, ldapSearchFilter);
  716.     }
  717.  
  718.     public String getLdapManagerDn() {
  719.         return properties.getProperty(KEY_LDAP_MANAGER_DN, DEFAULT_LDAP_MANAGER_DN);
  720.     }
  721.  
  722.     public void setLdapManagerDn(String ldapManagerDn) {
  723.         properties.setProperty(KEY_LDAP_MANAGER_DN, ldapManagerDn);
  724.     }
  725.  
  726.     public String getLdapManagerPassword() {
  727.         String s = properties.getProperty(KEY_LDAP_MANAGER_PASSWORD, DEFAULT_LDAP_MANAGER_PASSWORD);
  728.         try {
  729.             return StringUtil.utf8HexDecode(s);
  730.         } catch (Exception x) {
  731.             LOG.warn("Failed to decode LDAP manager password.", x);
  732.             return s;
  733.         }
  734.     }
  735.  
  736.     public void setLdapManagerPassword(String ldapManagerPassword) {
  737.         try {
  738.             ldapManagerPassword = StringUtil.utf8HexEncode(ldapManagerPassword);
  739.         } catch (Exception x) {
  740.             LOG.warn("Failed to encode LDAP manager password.", x);
  741.         }
  742.         properties.setProperty(KEY_LDAP_MANAGER_PASSWORD, ldapManagerPassword);
  743.     }
  744.  
  745.     public boolean isLdapAutoShadowing() {
  746.         return getBoolean(KEY_LDAP_AUTO_SHADOWING, DEFAULT_LDAP_AUTO_SHADOWING);
  747.     }
  748.  
  749.     public void setLdapAutoShadowing(boolean ldapAutoShadowing) {
  750.         setBoolean(KEY_LDAP_AUTO_SHADOWING, ldapAutoShadowing);
  751.     }
  752.  
  753.     public boolean isGettingStartedEnabled() {
  754.         return getBoolean(KEY_GETTING_STARTED_ENABLED, DEFAULT_GETTING_STARTED_ENABLED);
  755.     }
  756.  
  757.     public void setGettingStartedEnabled(boolean isGettingStartedEnabled) {
  758.         setBoolean(KEY_GETTING_STARTED_ENABLED, isGettingStartedEnabled);
  759.     }
  760.  
  761.     public boolean isPortForwardingEnabled() {
  762.         return getBoolean(KEY_PORT_FORWARDING_ENABLED, DEFAULT_PORT_FORWARDING_ENABLED);
  763.     }
  764.  
  765.     public void setPortForwardingEnabled(boolean isPortForwardingEnabled) {
  766.         setBoolean(KEY_PORT_FORWARDING_ENABLED, isPortForwardingEnabled);
  767.     }
  768.  
  769.     public int getPort() {
  770.         return Integer.valueOf(properties.getProperty(KEY_PORT, String.valueOf(DEFAULT_PORT)));
  771.     }
  772.  
  773.     public void setPort(int port) {
  774.         setProperty(KEY_PORT, String.valueOf(port));
  775.     }
  776.  
  777.     public int getHttpsPort() {
  778.         return Integer.valueOf(properties.getProperty(KEY_HTTPS_PORT, String.valueOf(DEFAULT_HTTPS_PORT)));
  779.     }
  780.  
  781.     public void setHttpsPort(int httpsPort) {
  782.         setProperty(KEY_HTTPS_PORT, String.valueOf(httpsPort));
  783.     }
  784.  
  785.     public boolean isUrlRedirectionEnabled() {
  786.         return getBoolean(KEY_URL_REDIRECTION_ENABLED, DEFAULT_URL_REDIRECTION_ENABLED);
  787.     }
  788.  
  789.     public void setUrlRedirectionEnabled(boolean isUrlRedirectionEnabled) {
  790.         setBoolean(KEY_URL_REDIRECTION_ENABLED, isUrlRedirectionEnabled);
  791.     }
  792.  
  793.     public String getUrlRedirectFrom() {
  794.         return properties.getProperty(KEY_URL_REDIRECT_FROM, DEFAULT_URL_REDIRECT_FROM);
  795.     }
  796.  
  797.     public void setUrlRedirectFrom(String urlRedirectFrom) {
  798.         properties.setProperty(KEY_URL_REDIRECT_FROM, urlRedirectFrom);
  799.     }
  800.  
  801.     public Date getTrialExpires() {
  802.         String value = properties.getProperty(KEY_TRIAL_EXPIRES, DEFAULT_TRIAL_EXPIRES);
  803.         return value == null ? null : new Date(Long.parseLong(value));
  804.     }
  805.  
  806.     private void setTrialExpires(Date date) {
  807.         String value = (date == null ? null : String.valueOf(date.getTime()));
  808.         setProperty(KEY_TRIAL_EXPIRES, value);
  809.     }
  810.  
  811.     public String getUrlRedirectContextPath() {
  812.         return properties.getProperty(KEY_URL_REDIRECT_CONTEXT_PATH, DEFAULT_URL_REDIRECT_CONTEXT_PATH);
  813.     }
  814.  
  815.     public void setUrlRedirectContextPath(String contextPath) {
  816.         properties.setProperty(KEY_URL_REDIRECT_CONTEXT_PATH, contextPath);
  817.     }
  818.  
  819.     public String getServerId() {
  820.         return properties.getProperty(KEY_SERVER_ID, DEFAULT_SERVER_ID);
  821.     }
  822.  
  823.     public void setServerId(String serverId) {
  824.         properties.setProperty(KEY_SERVER_ID, serverId);
  825.     }
  826.  
  827.     public long getSettingsChanged() {
  828.         return Long.parseLong(properties.getProperty(KEY_SETTINGS_CHANGED, String.valueOf(DEFAULT_SETTINGS_CHANGED)));
  829.     }
  830.  
  831.     public Date getLastScanned() {
  832.         String lastScanned = properties.getProperty(KEY_LAST_SCANNED);
  833.         return lastScanned == null ? null : new Date(Long.parseLong(lastScanned));
  834.     }
  835.  
  836.     public void setLastScanned(Date date) {
  837.         if (date == null) {
  838.             properties.remove(KEY_LAST_SCANNED);
  839.         } else {
  840.             properties.setProperty(KEY_LAST_SCANNED, String.valueOf(date.getTime()));
  841.         }
  842.     }
  843.  
  844.     public boolean isOrganizeByFolderStructure() {
  845.         return getBoolean(KEY_ORGANIZE_BY_FOLDER_STRUCTURE, DEFAULT_ORGANIZE_BY_FOLDER_STRUCTURE);
  846.     }
  847.  
  848.     public void setOrganizeByFolderStructure(boolean b) {
  849.         setBoolean(KEY_ORGANIZE_BY_FOLDER_STRUCTURE, b);
  850.     }
  851.  
  852.     public boolean isSortAlbumsByYear() {
  853.         return getBoolean(KEY_SORT_ALBUMS_BY_YEAR, DEFAULT_SORT_ALBUMS_BY_YEAR);
  854.     }
  855.  
  856.     public void setSortAlbumsByYear(boolean b) {
  857.         setBoolean(KEY_SORT_ALBUMS_BY_YEAR, b);
  858.     }
  859.  
  860.     public MediaLibraryStatistics getMediaLibraryStatistics() {
  861.         return MediaLibraryStatistics.parse(getString(KEY_MEDIA_LIBRARY_STATISTICS, DEFAULT_MEDIA_LIBRARY_STATISTICS));
  862.     }
  863.  
  864.     public void setMediaLibraryStatistics(MediaLibraryStatistics statistics) {
  865.         setString(KEY_MEDIA_LIBRARY_STATISTICS, statistics.format());
  866.     }
  867.  
  868.     /**
  869.      * Returns the locale (for language, date format etc).
  870.      *
  871.      * @return The locale.
  872.      */
  873.     public Locale getLocale() {
  874.         String language = properties.getProperty(KEY_LOCALE_LANGUAGE, DEFAULT_LOCALE_LANGUAGE);
  875.         String country = properties.getProperty(KEY_LOCALE_COUNTRY, DEFAULT_LOCALE_COUNTRY);
  876.         String variant = properties.getProperty(KEY_LOCALE_VARIANT, DEFAULT_LOCALE_VARIANT);
  877.  
  878.         return new Locale(language, country, variant);
  879.     }
  880.  
  881.     /**
  882.      * Sets the locale (for language, date format etc.)
  883.      *
  884.      * @param locale The locale.
  885.      */
  886.     public void setLocale(Locale locale) {
  887.         setProperty(KEY_LOCALE_LANGUAGE, locale.getLanguage());
  888.         setProperty(KEY_LOCALE_COUNTRY, locale.getCountry());
  889.         setProperty(KEY_LOCALE_VARIANT, locale.getVariant());
  890.     }
  891.  
  892.     /**
  893.      * Returns the ID of the theme to use.
  894.      *
  895.      * @return The theme ID.
  896.      */
  897.     public String getThemeId() {
  898.         return properties.getProperty(KEY_THEME_ID, DEFAULT_THEME_ID);
  899.     }
  900.  
  901.     /**
  902.      * Sets the ID of the theme to use.
  903.      *
  904.      * @param themeId The theme ID
  905.      */
  906.     public void setThemeId(String themeId) {
  907.         setProperty(KEY_THEME_ID, themeId);
  908.     }
  909.  
  910.     /**
  911.      * Returns a list of available themes.
  912.      *
  913.      * @return A list of available themes.
  914.      */
  915.     public synchronized Theme[] getAvailableThemes() {
  916.         if (themes == null) {
  917.             themes = new ArrayList<Theme>();
  918.             try {
  919.                 InputStream in = SettingsService.class.getResourceAsStream(THEMES_FILE);
  920.                 String[] lines = StringUtil.readLines(in);
  921.                 for (String line : lines) {
  922.                     String[] elements = StringUtil.split(line);
  923.                     if (elements.length == 2) {
  924.                         themes.add(new Theme(elements[0], elements[1]));
  925.                     } else if (elements.length == 3) {
  926.                         themes.add(new Theme(elements[0], elements[1], elements[2]));
  927.                     } else {
  928.                         LOG.warn("Failed to parse theme from line: [" + line + "].");
  929.                     }
  930.                 }
  931.             } catch (IOException x) {
  932.                 LOG.error("Failed to resolve list of themes.", x);
  933.                 themes.add(new Theme("default", "Subsonic default"));
  934.             }
  935.         }
  936.         return themes.toArray(new Theme[themes.size()]);
  937.     }
  938.  
  939.     /**
  940.      * Returns a list of available locales.
  941.      *
  942.      * @return A list of available locales.
  943.      */
  944.     public synchronized Locale[] getAvailableLocales() {
  945.         if (locales == null) {
  946.             locales = new ArrayList<Locale>();
  947.             try {
  948.                 InputStream in = SettingsService.class.getResourceAsStream(LOCALES_FILE);
  949.                 String[] lines = StringUtil.readLines(in);
  950.  
  951.                 for (String line : lines) {
  952.                     locales.add(parseLocale(line));
  953.                 }
  954.  
  955.             } catch (IOException x) {
  956.                 LOG.error("Failed to resolve list of locales.", x);
  957.                 locales.add(Locale.ENGLISH);
  958.             }
  959.         }
  960.         return locales.toArray(new Locale[locales.size()]);
  961.     }
  962.  
  963.     private Locale parseLocale(String line) {
  964.         String[] s = line.split("_");
  965.         String language = s[0];
  966.         String country = "";
  967.         String variant = "";
  968.  
  969.         if (s.length > 1) {
  970.             country = s[1];
  971.         }
  972.         if (s.length > 2) {
  973.             variant = s[2];
  974.         }
  975.         return new Locale(language, country, variant);
  976.     }
  977.  
  978.     /**
  979.      * Returns the "brand" name. Normally, this is just "Subsonic".
  980.      *
  981.      * @return The brand name.
  982.      */
  983.     public String getBrand() {
  984.         return "Subsonic";
  985.     }
  986.  
  987.     /**
  988.      * Returns all music folders. Non-existing and disabled folders are not included.
  989.      *
  990.      * @return Possibly empty list of all music folders.
  991.      */
  992.     public List<MusicFolder> getAllMusicFolders() {
  993.         return getAllMusicFolders(false, false);
  994.     }
  995.  
  996.     /**
  997.      * Returns all music folders.
  998.      *
  999.      * @param includeDisabled Whether to include disabled folders.
  1000.      * @param includeNonExisting Whether to include non-existing folders.
  1001.      * @return Possibly empty list of all music folders.
  1002.      */
  1003.     public List<MusicFolder> getAllMusicFolders(boolean includeDisabled, boolean includeNonExisting) {
  1004.         if (cachedMusicFolders == null) {
  1005.             cachedMusicFolders = musicFolderDao.getAllMusicFolders();
  1006.         }
  1007.        
  1008.         List<MusicFolder> result = new ArrayList<MusicFolder>(cachedMusicFolders.size());
  1009.         for (MusicFolder folder : cachedMusicFolders) {
  1010.             if ((includeDisabled || folder.isEnabled()) && (includeNonExisting || FileUtil.exists(folder.getPath()))) {
  1011.                 result.add(folder);
  1012.             }
  1013.         }
  1014.         return result;
  1015.     }
  1016.  
  1017.     /**
  1018.      * Returns the music folder with the given ID.
  1019.      *
  1020.      * @param id The ID.
  1021.      * @return The music folder with the given ID, or <code>null</code> if not found.
  1022.      */
  1023.     public MusicFolder getMusicFolderById(Integer id) {
  1024.         List<MusicFolder> all = getAllMusicFolders();
  1025.         for (MusicFolder folder : all) {
  1026.             if (id.equals(folder.getId())) {
  1027.                 return folder;
  1028.             }
  1029.         }
  1030.         return null;
  1031.     }
  1032.  
  1033.     /**
  1034.      * Creates a new music folder.
  1035.      *
  1036.      * @param musicFolder The music folder to create.
  1037.      */
  1038.     public void createMusicFolder(MusicFolder musicFolder) {
  1039.         musicFolderDao.createMusicFolder(musicFolder);
  1040.         cachedMusicFolders = null;
  1041.     }
  1042.  
  1043.     /**
  1044.      * Deletes the music folder with the given ID.
  1045.      *
  1046.      * @param id The ID of the music folder to delete.
  1047.      */
  1048.     public void deleteMusicFolder(Integer id) {
  1049.         musicFolderDao.deleteMusicFolder(id);
  1050.         cachedMusicFolders = null;
  1051.     }
  1052.  
  1053.     /**
  1054.      * Updates the given music folder.
  1055.      *
  1056.      * @param musicFolder The music folder to update.
  1057.      */
  1058.     public void updateMusicFolder(MusicFolder musicFolder) {
  1059.         musicFolderDao.updateMusicFolder(musicFolder);
  1060.         cachedMusicFolders = null;
  1061.     }
  1062.  
  1063.     /**
  1064.      * Returns all internet radio stations. Disabled stations are not returned.
  1065.      *
  1066.      * @return Possibly empty list of all internet radio stations.
  1067.      */
  1068.     public List<InternetRadio> getAllInternetRadios() {
  1069.         return getAllInternetRadios(false);
  1070.     }
  1071.  
  1072.     /**
  1073.      * Returns the internet radio station with the given ID.
  1074.      *
  1075.      * @param id The ID.
  1076.      * @return The internet radio station with the given ID, or <code>null</code> if not found.
  1077.      */
  1078.     public InternetRadio getInternetRadioById(Integer id) {
  1079.         for (InternetRadio radio : getAllInternetRadios()) {
  1080.             if (id.equals(radio.getId())) {
  1081.                 return radio;
  1082.             }
  1083.         }
  1084.         return null;
  1085.     }
  1086.  
  1087.     /**
  1088.      * Returns all internet radio stations.
  1089.      *
  1090.      * @param includeAll Whether disabled stations should be included.
  1091.      * @return Possibly empty list of all internet radio stations.
  1092.      */
  1093.     public List<InternetRadio> getAllInternetRadios(boolean includeAll) {
  1094.         List<InternetRadio> all = internetRadioDao.getAllInternetRadios();
  1095.         List<InternetRadio> result = new ArrayList<InternetRadio>(all.size());
  1096.         for (InternetRadio folder : all) {
  1097.             if (includeAll || folder.isEnabled()) {
  1098.                 result.add(folder);
  1099.             }
  1100.         }
  1101.         return result;
  1102.     }
  1103.  
  1104.     /**
  1105.      * Creates a new internet radio station.
  1106.      *
  1107.      * @param radio The internet radio station to create.
  1108.      */
  1109.     public void createInternetRadio(InternetRadio radio) {
  1110.         internetRadioDao.createInternetRadio(radio);
  1111.     }
  1112.  
  1113.     /**
  1114.      * Deletes the internet radio station with the given ID.
  1115.      *
  1116.      * @param id The internet radio station ID.
  1117.      */
  1118.     public void deleteInternetRadio(Integer id) {
  1119.         internetRadioDao.deleteInternetRadio(id);
  1120.     }
  1121.  
  1122.     /**
  1123.      * Updates the given internet radio station.
  1124.      *
  1125.      * @param radio The internet radio station to update.
  1126.      */
  1127.     public void updateInternetRadio(InternetRadio radio) {
  1128.         internetRadioDao.updateInternetRadio(radio);
  1129.     }
  1130.  
  1131.     /**
  1132.      * Returns settings for the given user.
  1133.      *
  1134.      * @param username The username.
  1135.      * @return User-specific settings. Never <code>null</code>.
  1136.      */
  1137.     public UserSettings getUserSettings(String username) {
  1138.         UserSettings settings = userDao.getUserSettings(username);
  1139.         return settings == null ? createDefaultUserSettings(username) : settings;
  1140.     }
  1141.  
  1142.     private UserSettings createDefaultUserSettings(String username) {
  1143.         UserSettings settings = new UserSettings(username);
  1144.         settings.setFinalVersionNotificationEnabled(true);
  1145.         settings.setBetaVersionNotificationEnabled(false);
  1146.         settings.setSongNotificationEnabled(true);
  1147.         settings.setShowNowPlayingEnabled(true);
  1148.         settings.setShowChatEnabled(true);
  1149.         settings.setPartyModeEnabled(false);
  1150.         settings.setNowPlayingAllowed(true);
  1151.         settings.setLastFmEnabled(false);
  1152.         settings.setLastFmUsername(null);
  1153.         settings.setLastFmPassword(null);
  1154.         settings.setChanged(new Date());
  1155.  
  1156.         UserSettings.Visibility playlist = settings.getPlaylistVisibility();
  1157.         playlist.setCaptionCutoff(35);
  1158.         playlist.setArtistVisible(true);
  1159.         playlist.setAlbumVisible(true);
  1160.         playlist.setYearVisible(true);
  1161.         playlist.setDurationVisible(true);
  1162.         playlist.setBitRateVisible(true);
  1163.         playlist.setFormatVisible(true);
  1164.         playlist.setFileSizeVisible(true);
  1165.  
  1166.         UserSettings.Visibility main = settings.getMainVisibility();
  1167.         main.setCaptionCutoff(35);
  1168.         main.setTrackNumberVisible(true);
  1169.         main.setArtistVisible(true);
  1170.         main.setDurationVisible(true);
  1171.  
  1172.         return settings;
  1173.     }
  1174.  
  1175.     /**
  1176.      * Updates settings for the given username.
  1177.      *
  1178.      * @param settings The user-specific settings.
  1179.      */
  1180.     public void updateUserSettings(UserSettings settings) {
  1181.         userDao.updateUserSettings(settings);
  1182.     }
  1183.  
  1184.     /**
  1185.      * Returns all system avatars.
  1186.      *
  1187.      * @return All system avatars.
  1188.      */
  1189.     public List<Avatar> getAllSystemAvatars() {
  1190.         return avatarDao.getAllSystemAvatars();
  1191.     }
  1192.  
  1193.     /**
  1194.      * Returns the system avatar with the given ID.
  1195.      *
  1196.      * @param id The system avatar ID.
  1197.      * @return The avatar or <code>null</code> if not found.
  1198.      */
  1199.     public Avatar getSystemAvatar(int id) {
  1200.         return avatarDao.getSystemAvatar(id);
  1201.     }
  1202.  
  1203.     /**
  1204.      * Returns the custom avatar for the given user.
  1205.      *
  1206.      * @param username The username.
  1207.      * @return The avatar or <code>null</code> if not found.
  1208.      */
  1209.     public Avatar getCustomAvatar(String username) {
  1210.         return avatarDao.getCustomAvatar(username);
  1211.     }
  1212.  
  1213.     /**
  1214.      * Sets the custom avatar for the given user.
  1215.      *
  1216.      * @param avatar   The avatar, or <code>null</code> to remove the avatar.
  1217.      * @param username The username.
  1218.      */
  1219.     public void setCustomAvatar(Avatar avatar, String username) {
  1220.         avatarDao.setCustomAvatar(avatar, username);
  1221.     }
  1222.  
  1223.     public boolean isDlnaEnabled() {
  1224.         return getBoolean(KEY_DLNA_ENABLED, DEFAULT_DLNA_ENABLED);
  1225.     }
  1226.  
  1227.     public void setDlnaEnabled(boolean dlnaEnabled) {
  1228.         setBoolean(KEY_DLNA_ENABLED, dlnaEnabled);
  1229.     }
  1230.  
  1231.     public String getDlnaServerName() {
  1232.         return getString(KEY_DLNA_SERVER_NAME, DEFAULT_DLNA_SERVER_NAME);
  1233.     }
  1234.  
  1235.     public void setDlnaServerName(String dlnaServerName) {
  1236.         setString(KEY_DLNA_SERVER_NAME, dlnaServerName);
  1237.     }
  1238.  
  1239.     public String getLocalIpAddress() {
  1240.         return localIpAddress;
  1241.     }
  1242.  
  1243.     private void setProperty(String key, String value) {
  1244.         if (value == null) {
  1245.             properties.remove(key);
  1246.         } else {
  1247.             properties.setProperty(key, value);
  1248.         }
  1249.     }
  1250.  
  1251.     private String[] toStringArray(String s) {
  1252.         List<String> result = new ArrayList<String>();
  1253.         StringTokenizer tokenizer = new StringTokenizer(s, " ");
  1254.         while (tokenizer.hasMoreTokens()) {
  1255.             result.add(tokenizer.nextToken());
  1256.         }
  1257.  
  1258.         return result.toArray(new String[result.size()]);
  1259.     }
  1260.  
  1261.     private void validateLicense() {
  1262.         String email = getLicenseEmail();
  1263.         Date date = getLicenseDate();
  1264.         licenseValidated = true;
  1265.         return;
  1266.     }
  1267.  
  1268.     public synchronized void scheduleLicenseValidation() {
  1269.         if (licenseValidationFuture != null) {
  1270.             licenseValidationFuture.cancel(true);
  1271.         }
  1272.         Runnable task = new Runnable() {
  1273.             public void run() {
  1274.                 validateLicense();
  1275.             }
  1276.         };
  1277.         licenseValidationFuture = executor.scheduleWithFixedDelay(task, 0L, LICENSE_VALIDATION_DELAY_HOURS, TimeUnit.HOURS);
  1278.     }
  1279.  
  1280.     private void scheduleLocalIpAddressLookup() {
  1281.         Runnable task = new Runnable() {
  1282.             public void run() {
  1283.                 localIpAddress = Util.getLocalIpAddress();
  1284.             }
  1285.         };
  1286.         executor.scheduleWithFixedDelay(task, 0L, LOCAL_IP_LOOKUP_DELAY_SECONDS, TimeUnit.SECONDS);
  1287.     }
  1288.  
  1289.     public void setInternetRadioDao(InternetRadioDao internetRadioDao) {
  1290.         this.internetRadioDao = internetRadioDao;
  1291.     }
  1292.  
  1293.     public void setMusicFolderDao(MusicFolderDao musicFolderDao) {
  1294.         this.musicFolderDao = musicFolderDao;
  1295.     }
  1296.  
  1297.     public void setUserDao(UserDao userDao) {
  1298.         this.userDao = userDao;
  1299.     }
  1300.  
  1301.     public void setAvatarDao(AvatarDao avatarDao) {
  1302.         this.avatarDao = avatarDao;
  1303.     }
  1304.  
  1305.     public void setVersionService(VersionService versionService) {
  1306.         this.versionService = versionService;
  1307.     }
  1308. }
RAW Paste Data
We use cookies for various purposes including analytics. By continuing to use Pastebin, you agree to our use of cookies as described in the Cookies Policy. OK, I Understand
 
Top