Advertisement
Guest User

Untitled

a guest
Sep 24th, 2014
394
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Java 49.77 KB | None | 0 0
  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 isLicenseValid(getLicenseEmail(), getLicenseCode()) && licenseValidated;
  651.     }
  652.  
  653.     public boolean isLicenseValid(String email, String license) {
  654.         if (email == null || license == null) {
  655.             return false;
  656.         }
  657.         return license.equalsIgnoreCase(StringUtil.md5Hex(email.toLowerCase()));
  658.     }
  659.  
  660.     public LicenseInfo getLicenseInfo() {
  661.         Date trialExpires = getTrialExpires();
  662.         Date now = new Date();
  663.         boolean trialValid = trialExpires.after(now);
  664.         long trialDaysLeft = trialValid ? (trialExpires.getTime() - now.getTime()) / (24L * 3600L * 1000L) : 0L;
  665.  
  666.         return new LicenseInfo(getLicenseEmail(), isLicenseValid(), trialExpires, trialDaysLeft, licenseExpires);
  667.     }
  668.  
  669.     public String getDownsamplingCommand() {
  670.         return properties.getProperty(KEY_DOWNSAMPLING_COMMAND, DEFAULT_DOWNSAMPLING_COMMAND);
  671.     }
  672.  
  673.     public void setDownsamplingCommand(String command) {
  674.         setProperty(KEY_DOWNSAMPLING_COMMAND, command);
  675.     }
  676.  
  677.     public String getHlsCommand() {
  678.         return properties.getProperty(KEY_HLS_COMMAND, DEFAULT_HLS_COMMAND);
  679.     }
  680.  
  681.     public void setHlsCommand(String command) {
  682.         setProperty(KEY_HLS_COMMAND, command);
  683.     }
  684.  
  685.     public String getJukeboxCommand() {
  686.         return properties.getProperty(KEY_JUKEBOX_COMMAND, DEFAULT_JUKEBOX_COMMAND);
  687.     }
  688.  
  689.     public boolean isRewriteUrlEnabled() {
  690.         return getBoolean(KEY_REWRITE_URL, DEFAULT_REWRITE_URL);
  691.     }
  692.  
  693.     public void setRewriteUrlEnabled(boolean rewriteUrl) {
  694.         setBoolean(KEY_REWRITE_URL, rewriteUrl);
  695.     }
  696.  
  697.     public boolean isLdapEnabled() {
  698.         return getBoolean(KEY_LDAP_ENABLED, DEFAULT_LDAP_ENABLED);
  699.     }
  700.  
  701.     public void setLdapEnabled(boolean ldapEnabled) {
  702.         setBoolean(KEY_LDAP_ENABLED, ldapEnabled);
  703.     }
  704.  
  705.     public String getLdapUrl() {
  706.         return properties.getProperty(KEY_LDAP_URL, DEFAULT_LDAP_URL);
  707.     }
  708.  
  709.     public void setLdapUrl(String ldapUrl) {
  710.         properties.setProperty(KEY_LDAP_URL, ldapUrl);
  711.     }
  712.  
  713.     public String getLdapSearchFilter() {
  714.         return properties.getProperty(KEY_LDAP_SEARCH_FILTER, DEFAULT_LDAP_SEARCH_FILTER);
  715.     }
  716.  
  717.     public void setLdapSearchFilter(String ldapSearchFilter) {
  718.         properties.setProperty(KEY_LDAP_SEARCH_FILTER, ldapSearchFilter);
  719.     }
  720.  
  721.     public String getLdapManagerDn() {
  722.         return properties.getProperty(KEY_LDAP_MANAGER_DN, DEFAULT_LDAP_MANAGER_DN);
  723.     }
  724.  
  725.     public void setLdapManagerDn(String ldapManagerDn) {
  726.         properties.setProperty(KEY_LDAP_MANAGER_DN, ldapManagerDn);
  727.     }
  728.  
  729.     public String getLdapManagerPassword() {
  730.         String s = properties.getProperty(KEY_LDAP_MANAGER_PASSWORD, DEFAULT_LDAP_MANAGER_PASSWORD);
  731.         try {
  732.             return StringUtil.utf8HexDecode(s);
  733.         } catch (Exception x) {
  734.             LOG.warn("Failed to decode LDAP manager password.", x);
  735.             return s;
  736.         }
  737.     }
  738.  
  739.     public void setLdapManagerPassword(String ldapManagerPassword) {
  740.         try {
  741.             ldapManagerPassword = StringUtil.utf8HexEncode(ldapManagerPassword);
  742.         } catch (Exception x) {
  743.             LOG.warn("Failed to encode LDAP manager password.", x);
  744.         }
  745.         properties.setProperty(KEY_LDAP_MANAGER_PASSWORD, ldapManagerPassword);
  746.     }
  747.  
  748.     public boolean isLdapAutoShadowing() {
  749.         return getBoolean(KEY_LDAP_AUTO_SHADOWING, DEFAULT_LDAP_AUTO_SHADOWING);
  750.     }
  751.  
  752.     public void setLdapAutoShadowing(boolean ldapAutoShadowing) {
  753.         setBoolean(KEY_LDAP_AUTO_SHADOWING, ldapAutoShadowing);
  754.     }
  755.  
  756.     public boolean isGettingStartedEnabled() {
  757.         return getBoolean(KEY_GETTING_STARTED_ENABLED, DEFAULT_GETTING_STARTED_ENABLED);
  758.     }
  759.  
  760.     public void setGettingStartedEnabled(boolean isGettingStartedEnabled) {
  761.         setBoolean(KEY_GETTING_STARTED_ENABLED, isGettingStartedEnabled);
  762.     }
  763.  
  764.     public boolean isPortForwardingEnabled() {
  765.         return getBoolean(KEY_PORT_FORWARDING_ENABLED, DEFAULT_PORT_FORWARDING_ENABLED);
  766.     }
  767.  
  768.     public void setPortForwardingEnabled(boolean isPortForwardingEnabled) {
  769.         setBoolean(KEY_PORT_FORWARDING_ENABLED, isPortForwardingEnabled);
  770.     }
  771.  
  772.     public int getPort() {
  773.         return Integer.valueOf(properties.getProperty(KEY_PORT, String.valueOf(DEFAULT_PORT)));
  774.     }
  775.  
  776.     public void setPort(int port) {
  777.         setProperty(KEY_PORT, String.valueOf(port));
  778.     }
  779.  
  780.     public int getHttpsPort() {
  781.         return Integer.valueOf(properties.getProperty(KEY_HTTPS_PORT, String.valueOf(DEFAULT_HTTPS_PORT)));
  782.     }
  783.  
  784.     public void setHttpsPort(int httpsPort) {
  785.         setProperty(KEY_HTTPS_PORT, String.valueOf(httpsPort));
  786.     }
  787.  
  788.     public boolean isUrlRedirectionEnabled() {
  789.         return getBoolean(KEY_URL_REDIRECTION_ENABLED, DEFAULT_URL_REDIRECTION_ENABLED);
  790.     }
  791.  
  792.     public void setUrlRedirectionEnabled(boolean isUrlRedirectionEnabled) {
  793.         setBoolean(KEY_URL_REDIRECTION_ENABLED, isUrlRedirectionEnabled);
  794.     }
  795.  
  796.     public String getUrlRedirectFrom() {
  797.         return properties.getProperty(KEY_URL_REDIRECT_FROM, DEFAULT_URL_REDIRECT_FROM);
  798.     }
  799.  
  800.     public void setUrlRedirectFrom(String urlRedirectFrom) {
  801.         properties.setProperty(KEY_URL_REDIRECT_FROM, urlRedirectFrom);
  802.     }
  803.  
  804.     public Date getTrialExpires() {
  805.         String value = properties.getProperty(KEY_TRIAL_EXPIRES, DEFAULT_TRIAL_EXPIRES);
  806.         return value == null ? null : new Date(Long.parseLong(value));
  807.     }
  808.  
  809.     private void setTrialExpires(Date date) {
  810.         String value = (date == null ? null : String.valueOf(date.getTime()));
  811.         setProperty(KEY_TRIAL_EXPIRES, value);
  812.     }
  813.  
  814.     public String getUrlRedirectContextPath() {
  815.         return properties.getProperty(KEY_URL_REDIRECT_CONTEXT_PATH, DEFAULT_URL_REDIRECT_CONTEXT_PATH);
  816.     }
  817.  
  818.     public void setUrlRedirectContextPath(String contextPath) {
  819.         properties.setProperty(KEY_URL_REDIRECT_CONTEXT_PATH, contextPath);
  820.     }
  821.  
  822.     public String getServerId() {
  823.         return properties.getProperty(KEY_SERVER_ID, DEFAULT_SERVER_ID);
  824.     }
  825.  
  826.     public void setServerId(String serverId) {
  827.         properties.setProperty(KEY_SERVER_ID, serverId);
  828.     }
  829.  
  830.     public long getSettingsChanged() {
  831.         return Long.parseLong(properties.getProperty(KEY_SETTINGS_CHANGED, String.valueOf(DEFAULT_SETTINGS_CHANGED)));
  832.     }
  833.  
  834.     public Date getLastScanned() {
  835.         String lastScanned = properties.getProperty(KEY_LAST_SCANNED);
  836.         return lastScanned == null ? null : new Date(Long.parseLong(lastScanned));
  837.     }
  838.  
  839.     public void setLastScanned(Date date) {
  840.         if (date == null) {
  841.             properties.remove(KEY_LAST_SCANNED);
  842.         } else {
  843.             properties.setProperty(KEY_LAST_SCANNED, String.valueOf(date.getTime()));
  844.         }
  845.     }
  846.  
  847.     public boolean isOrganizeByFolderStructure() {
  848.         return getBoolean(KEY_ORGANIZE_BY_FOLDER_STRUCTURE, DEFAULT_ORGANIZE_BY_FOLDER_STRUCTURE);
  849.     }
  850.  
  851.     public void setOrganizeByFolderStructure(boolean b) {
  852.         setBoolean(KEY_ORGANIZE_BY_FOLDER_STRUCTURE, b);
  853.     }
  854.  
  855.     public boolean isSortAlbumsByYear() {
  856.         return getBoolean(KEY_SORT_ALBUMS_BY_YEAR, DEFAULT_SORT_ALBUMS_BY_YEAR);
  857.     }
  858.  
  859.     public void setSortAlbumsByYear(boolean b) {
  860.         setBoolean(KEY_SORT_ALBUMS_BY_YEAR, b);
  861.     }
  862.  
  863.     public MediaLibraryStatistics getMediaLibraryStatistics() {
  864.         return MediaLibraryStatistics.parse(getString(KEY_MEDIA_LIBRARY_STATISTICS, DEFAULT_MEDIA_LIBRARY_STATISTICS));
  865.     }
  866.  
  867.     public void setMediaLibraryStatistics(MediaLibraryStatistics statistics) {
  868.         setString(KEY_MEDIA_LIBRARY_STATISTICS, statistics.format());
  869.     }
  870.  
  871.     /**
  872.      * Returns the locale (for language, date format etc).
  873.      *
  874.      * @return The locale.
  875.      */
  876.     public Locale getLocale() {
  877.         String language = properties.getProperty(KEY_LOCALE_LANGUAGE, DEFAULT_LOCALE_LANGUAGE);
  878.         String country = properties.getProperty(KEY_LOCALE_COUNTRY, DEFAULT_LOCALE_COUNTRY);
  879.         String variant = properties.getProperty(KEY_LOCALE_VARIANT, DEFAULT_LOCALE_VARIANT);
  880.  
  881.         return new Locale(language, country, variant);
  882.     }
  883.  
  884.     /**
  885.      * Sets the locale (for language, date format etc.)
  886.      *
  887.      * @param locale The locale.
  888.      */
  889.     public void setLocale(Locale locale) {
  890.         setProperty(KEY_LOCALE_LANGUAGE, locale.getLanguage());
  891.         setProperty(KEY_LOCALE_COUNTRY, locale.getCountry());
  892.         setProperty(KEY_LOCALE_VARIANT, locale.getVariant());
  893.     }
  894.  
  895.     /**
  896.      * Returns the ID of the theme to use.
  897.      *
  898.      * @return The theme ID.
  899.      */
  900.     public String getThemeId() {
  901.         return properties.getProperty(KEY_THEME_ID, DEFAULT_THEME_ID);
  902.     }
  903.  
  904.     /**
  905.      * Sets the ID of the theme to use.
  906.      *
  907.      * @param themeId The theme ID
  908.      */
  909.     public void setThemeId(String themeId) {
  910.         setProperty(KEY_THEME_ID, themeId);
  911.     }
  912.  
  913.     /**
  914.      * Returns a list of available themes.
  915.      *
  916.      * @return A list of available themes.
  917.      */
  918.     public synchronized Theme[] getAvailableThemes() {
  919.         if (themes == null) {
  920.             themes = new ArrayList<Theme>();
  921.             try {
  922.                 InputStream in = SettingsService.class.getResourceAsStream(THEMES_FILE);
  923.                 String[] lines = StringUtil.readLines(in);
  924.                 for (String line : lines) {
  925.                     String[] elements = StringUtil.split(line);
  926.                     if (elements.length == 2) {
  927.                         themes.add(new Theme(elements[0], elements[1]));
  928.                     } else if (elements.length == 3) {
  929.                         themes.add(new Theme(elements[0], elements[1], elements[2]));
  930.                     } else {
  931.                         LOG.warn("Failed to parse theme from line: [" + line + "].");
  932.                     }
  933.                 }
  934.             } catch (IOException x) {
  935.                 LOG.error("Failed to resolve list of themes.", x);
  936.                 themes.add(new Theme("default", "Subsonic default"));
  937.             }
  938.         }
  939.         return themes.toArray(new Theme[themes.size()]);
  940.     }
  941.  
  942.     /**
  943.      * Returns a list of available locales.
  944.      *
  945.      * @return A list of available locales.
  946.      */
  947.     public synchronized Locale[] getAvailableLocales() {
  948.         if (locales == null) {
  949.             locales = new ArrayList<Locale>();
  950.             try {
  951.                 InputStream in = SettingsService.class.getResourceAsStream(LOCALES_FILE);
  952.                 String[] lines = StringUtil.readLines(in);
  953.  
  954.                 for (String line : lines) {
  955.                     locales.add(parseLocale(line));
  956.                 }
  957.  
  958.             } catch (IOException x) {
  959.                 LOG.error("Failed to resolve list of locales.", x);
  960.                 locales.add(Locale.ENGLISH);
  961.             }
  962.         }
  963.         return locales.toArray(new Locale[locales.size()]);
  964.     }
  965.  
  966.     private Locale parseLocale(String line) {
  967.         String[] s = line.split("_");
  968.         String language = s[0];
  969.         String country = "";
  970.         String variant = "";
  971.  
  972.         if (s.length > 1) {
  973.             country = s[1];
  974.         }
  975.         if (s.length > 2) {
  976.             variant = s[2];
  977.         }
  978.         return new Locale(language, country, variant);
  979.     }
  980.  
  981.     /**
  982.      * Returns the "brand" name. Normally, this is just "Subsonic".
  983.      *
  984.      * @return The brand name.
  985.      */
  986.     public String getBrand() {
  987.         return "Subsonic";
  988.     }
  989.  
  990.     /**
  991.      * Returns all music folders. Non-existing and disabled folders are not included.
  992.      *
  993.      * @return Possibly empty list of all music folders.
  994.      */
  995.     public List<MusicFolder> getAllMusicFolders() {
  996.         return getAllMusicFolders(false, false);
  997.     }
  998.  
  999.     /**
  1000.      * Returns all music folders.
  1001.      *
  1002.      * @param includeDisabled Whether to include disabled folders.
  1003.      * @param includeNonExisting Whether to include non-existing folders.
  1004.      * @return Possibly empty list of all music folders.
  1005.      */
  1006.     public List<MusicFolder> getAllMusicFolders(boolean includeDisabled, boolean includeNonExisting) {
  1007.         if (cachedMusicFolders == null) {
  1008.             cachedMusicFolders = musicFolderDao.getAllMusicFolders();
  1009.         }
  1010.        
  1011.         List<MusicFolder> result = new ArrayList<MusicFolder>(cachedMusicFolders.size());
  1012.         for (MusicFolder folder : cachedMusicFolders) {
  1013.             if ((includeDisabled || folder.isEnabled()) && (includeNonExisting || FileUtil.exists(folder.getPath()))) {
  1014.                 result.add(folder);
  1015.             }
  1016.         }
  1017.         return result;
  1018.     }
  1019.  
  1020.     /**
  1021.      * Returns the music folder with the given ID.
  1022.      *
  1023.      * @param id The ID.
  1024.      * @return The music folder with the given ID, or <code>null</code> if not found.
  1025.      */
  1026.     public MusicFolder getMusicFolderById(Integer id) {
  1027.         List<MusicFolder> all = getAllMusicFolders();
  1028.         for (MusicFolder folder : all) {
  1029.             if (id.equals(folder.getId())) {
  1030.                 return folder;
  1031.             }
  1032.         }
  1033.         return null;
  1034.     }
  1035.  
  1036.     /**
  1037.      * Creates a new music folder.
  1038.      *
  1039.      * @param musicFolder The music folder to create.
  1040.      */
  1041.     public void createMusicFolder(MusicFolder musicFolder) {
  1042.         musicFolderDao.createMusicFolder(musicFolder);
  1043.         cachedMusicFolders = null;
  1044.     }
  1045.  
  1046.     /**
  1047.      * Deletes the music folder with the given ID.
  1048.      *
  1049.      * @param id The ID of the music folder to delete.
  1050.      */
  1051.     public void deleteMusicFolder(Integer id) {
  1052.         musicFolderDao.deleteMusicFolder(id);
  1053.         cachedMusicFolders = null;
  1054.     }
  1055.  
  1056.     /**
  1057.      * Updates the given music folder.
  1058.      *
  1059.      * @param musicFolder The music folder to update.
  1060.      */
  1061.     public void updateMusicFolder(MusicFolder musicFolder) {
  1062.         musicFolderDao.updateMusicFolder(musicFolder);
  1063.         cachedMusicFolders = null;
  1064.     }
  1065.  
  1066.     /**
  1067.      * Returns all internet radio stations. Disabled stations are not returned.
  1068.      *
  1069.      * @return Possibly empty list of all internet radio stations.
  1070.      */
  1071.     public List<InternetRadio> getAllInternetRadios() {
  1072.         return getAllInternetRadios(false);
  1073.     }
  1074.  
  1075.     /**
  1076.      * Returns the internet radio station with the given ID.
  1077.      *
  1078.      * @param id The ID.
  1079.      * @return The internet radio station with the given ID, or <code>null</code> if not found.
  1080.      */
  1081.     public InternetRadio getInternetRadioById(Integer id) {
  1082.         for (InternetRadio radio : getAllInternetRadios()) {
  1083.             if (id.equals(radio.getId())) {
  1084.                 return radio;
  1085.             }
  1086.         }
  1087.         return null;
  1088.     }
  1089.  
  1090.     /**
  1091.      * Returns all internet radio stations.
  1092.      *
  1093.      * @param includeAll Whether disabled stations should be included.
  1094.      * @return Possibly empty list of all internet radio stations.
  1095.      */
  1096.     public List<InternetRadio> getAllInternetRadios(boolean includeAll) {
  1097.         List<InternetRadio> all = internetRadioDao.getAllInternetRadios();
  1098.         List<InternetRadio> result = new ArrayList<InternetRadio>(all.size());
  1099.         for (InternetRadio folder : all) {
  1100.             if (includeAll || folder.isEnabled()) {
  1101.                 result.add(folder);
  1102.             }
  1103.         }
  1104.         return result;
  1105.     }
  1106.  
  1107.     /**
  1108.      * Creates a new internet radio station.
  1109.      *
  1110.      * @param radio The internet radio station to create.
  1111.      */
  1112.     public void createInternetRadio(InternetRadio radio) {
  1113.         internetRadioDao.createInternetRadio(radio);
  1114.     }
  1115.  
  1116.     /**
  1117.      * Deletes the internet radio station with the given ID.
  1118.      *
  1119.      * @param id The internet radio station ID.
  1120.      */
  1121.     public void deleteInternetRadio(Integer id) {
  1122.         internetRadioDao.deleteInternetRadio(id);
  1123.     }
  1124.  
  1125.     /**
  1126.      * Updates the given internet radio station.
  1127.      *
  1128.      * @param radio The internet radio station to update.
  1129.      */
  1130.     public void updateInternetRadio(InternetRadio radio) {
  1131.         internetRadioDao.updateInternetRadio(radio);
  1132.     }
  1133.  
  1134.     /**
  1135.      * Returns settings for the given user.
  1136.      *
  1137.      * @param username The username.
  1138.      * @return User-specific settings. Never <code>null</code>.
  1139.      */
  1140.     public UserSettings getUserSettings(String username) {
  1141.         UserSettings settings = userDao.getUserSettings(username);
  1142.         return settings == null ? createDefaultUserSettings(username) : settings;
  1143.     }
  1144.  
  1145.     private UserSettings createDefaultUserSettings(String username) {
  1146.         UserSettings settings = new UserSettings(username);
  1147.         settings.setFinalVersionNotificationEnabled(true);
  1148.         settings.setBetaVersionNotificationEnabled(false);
  1149.         settings.setSongNotificationEnabled(true);
  1150.         settings.setShowNowPlayingEnabled(true);
  1151.         settings.setShowChatEnabled(true);
  1152.         settings.setPartyModeEnabled(false);
  1153.         settings.setNowPlayingAllowed(true);
  1154.         settings.setLastFmEnabled(false);
  1155.         settings.setLastFmUsername(null);
  1156.         settings.setLastFmPassword(null);
  1157.         settings.setChanged(new Date());
  1158.  
  1159.         UserSettings.Visibility playlist = settings.getPlaylistVisibility();
  1160.         playlist.setCaptionCutoff(35);
  1161.         playlist.setArtistVisible(true);
  1162.         playlist.setAlbumVisible(true);
  1163.         playlist.setYearVisible(true);
  1164.         playlist.setDurationVisible(true);
  1165.         playlist.setBitRateVisible(true);
  1166.         playlist.setFormatVisible(true);
  1167.         playlist.setFileSizeVisible(true);
  1168.  
  1169.         UserSettings.Visibility main = settings.getMainVisibility();
  1170.         main.setCaptionCutoff(35);
  1171.         main.setTrackNumberVisible(true);
  1172.         main.setArtistVisible(true);
  1173.         main.setDurationVisible(true);
  1174.  
  1175.         return settings;
  1176.     }
  1177.  
  1178.     /**
  1179.      * Updates settings for the given username.
  1180.      *
  1181.      * @param settings The user-specific settings.
  1182.      */
  1183.     public void updateUserSettings(UserSettings settings) {
  1184.         userDao.updateUserSettings(settings);
  1185.     }
  1186.  
  1187.     /**
  1188.      * Returns all system avatars.
  1189.      *
  1190.      * @return All system avatars.
  1191.      */
  1192.     public List<Avatar> getAllSystemAvatars() {
  1193.         return avatarDao.getAllSystemAvatars();
  1194.     }
  1195.  
  1196.     /**
  1197.      * Returns the system avatar with the given ID.
  1198.      *
  1199.      * @param id The system avatar ID.
  1200.      * @return The avatar or <code>null</code> if not found.
  1201.      */
  1202.     public Avatar getSystemAvatar(int id) {
  1203.         return avatarDao.getSystemAvatar(id);
  1204.     }
  1205.  
  1206.     /**
  1207.      * Returns the custom avatar for the given user.
  1208.      *
  1209.      * @param username The username.
  1210.      * @return The avatar or <code>null</code> if not found.
  1211.      */
  1212.     public Avatar getCustomAvatar(String username) {
  1213.         return avatarDao.getCustomAvatar(username);
  1214.     }
  1215.  
  1216.     /**
  1217.      * Sets the custom avatar for the given user.
  1218.      *
  1219.      * @param avatar   The avatar, or <code>null</code> to remove the avatar.
  1220.      * @param username The username.
  1221.      */
  1222.     public void setCustomAvatar(Avatar avatar, String username) {
  1223.         avatarDao.setCustomAvatar(avatar, username);
  1224.     }
  1225.  
  1226.     public boolean isDlnaEnabled() {
  1227.         return getBoolean(KEY_DLNA_ENABLED, DEFAULT_DLNA_ENABLED);
  1228.     }
  1229.  
  1230.     public void setDlnaEnabled(boolean dlnaEnabled) {
  1231.         setBoolean(KEY_DLNA_ENABLED, dlnaEnabled);
  1232.     }
  1233.  
  1234.     public String getDlnaServerName() {
  1235.         return getString(KEY_DLNA_SERVER_NAME, DEFAULT_DLNA_SERVER_NAME);
  1236.     }
  1237.  
  1238.     public void setDlnaServerName(String dlnaServerName) {
  1239.         setString(KEY_DLNA_SERVER_NAME, dlnaServerName);
  1240.     }
  1241.  
  1242.     public String getLocalIpAddress() {
  1243.         return localIpAddress;
  1244.     }
  1245.  
  1246.     private void setProperty(String key, String value) {
  1247.         if (value == null) {
  1248.             properties.remove(key);
  1249.         } else {
  1250.             properties.setProperty(key, value);
  1251.         }
  1252.     }
  1253.  
  1254.     private String[] toStringArray(String s) {
  1255.         List<String> result = new ArrayList<String>();
  1256.         StringTokenizer tokenizer = new StringTokenizer(s, " ");
  1257.         while (tokenizer.hasMoreTokens()) {
  1258.             result.add(tokenizer.nextToken());
  1259.         }
  1260.  
  1261.         return result.toArray(new String[result.size()]);
  1262.     }
  1263.  
  1264.     private void validateLicense() {
  1265.         String email = getLicenseEmail();
  1266.         Date date = getLicenseDate();
  1267.  
  1268.         if (email == null || date == null) {
  1269.             licenseValidated = false;
  1270.             return;
  1271.         }
  1272.  
  1273.         licenseValidated = true;
  1274.  
  1275.         HttpClient client = new DefaultHttpClient();
  1276.         HttpConnectionParams.setConnectionTimeout(client.getParams(), 120000);
  1277.         HttpConnectionParams.setSoTimeout(client.getParams(), 120000);
  1278.         HttpGet method = new HttpGet("http://subsonic.org/backend/validateLicense.view" + "?email=" + StringUtil.urlEncode(email) +
  1279.                 "&date=" + date.getTime() + "&version=" + versionService.getLocalVersion());
  1280.         try {
  1281.             ResponseHandler<String> responseHandler = new BasicResponseHandler();
  1282.             String content = client.execute(method, responseHandler);
  1283.             licenseValidated = content != null && !content.contains("false");
  1284.             if (!licenseValidated) {
  1285.                 LOG.warn("License key is not valid.");
  1286.             }
  1287.             String[] lines = StringUtils.split(content);
  1288.             if (lines.length > 1) {
  1289.                 licenseExpires = new Date(Long.parseLong(lines[1]));
  1290.             }
  1291.  
  1292.         } catch (Throwable x) {
  1293.             LOG.warn("Failed to validate license.", x);
  1294.         } finally {
  1295.             client.getConnectionManager().shutdown();
  1296.         }
  1297.     }
  1298.  
  1299.     public synchronized void scheduleLicenseValidation() {
  1300.         if (licenseValidationFuture != null) {
  1301.             licenseValidationFuture.cancel(true);
  1302.         }
  1303.         Runnable task = new Runnable() {
  1304.             public void run() {
  1305.                 validateLicense();
  1306.             }
  1307.         };
  1308.         licenseValidationFuture = executor.scheduleWithFixedDelay(task, 0L, LICENSE_VALIDATION_DELAY_HOURS, TimeUnit.HOURS);
  1309.     }
  1310.  
  1311.     private void scheduleLocalIpAddressLookup() {
  1312.         Runnable task = new Runnable() {
  1313.             public void run() {
  1314.                 localIpAddress = Util.getLocalIpAddress();
  1315.             }
  1316.         };
  1317.         executor.scheduleWithFixedDelay(task, 0L, LOCAL_IP_LOOKUP_DELAY_SECONDS, TimeUnit.SECONDS);
  1318.     }
  1319.  
  1320.     public void setInternetRadioDao(InternetRadioDao internetRadioDao) {
  1321.         this.internetRadioDao = internetRadioDao;
  1322.     }
  1323.  
  1324.     public void setMusicFolderDao(MusicFolderDao musicFolderDao) {
  1325.         this.musicFolderDao = musicFolderDao;
  1326.     }
  1327.  
  1328.     public void setUserDao(UserDao userDao) {
  1329.         this.userDao = userDao;
  1330.     }
  1331.  
  1332.     public void setAvatarDao(AvatarDao avatarDao) {
  1333.         this.avatarDao = avatarDao;
  1334.     }
  1335.  
  1336.     public void setVersionService(VersionService versionService) {
  1337.         this.versionService = versionService;
  1338.     }
  1339. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement