diff --git a/Emby.Server.Implementations/AppBase/BaseApplicationPaths.cs b/Emby.Server.Implementations/AppBase/BaseApplicationPaths.cs
index 701c04f9e..f26cc4f62 100644
--- a/Emby.Server.Implementations/AppBase/BaseApplicationPaths.cs
+++ b/Emby.Server.Implementations/AppBase/BaseApplicationPaths.cs
@@ -1,3 +1,4 @@
+using System;
using System.IO;
using MediaBrowser.Common.Configuration;
@@ -14,50 +15,44 @@ namespace Emby.Server.Implementations.AppBase
///
protected BaseApplicationPaths(
string programDataPath,
- string appFolderPath,
- string logDirectoryPath = null,
- string configurationDirectoryPath = null,
- string cacheDirectoryPath = null)
+ string logDirectoryPath,
+ string configurationDirectoryPath,
+ string cacheDirectoryPath)
{
ProgramDataPath = programDataPath;
- ProgramSystemPath = appFolderPath;
LogDirectoryPath = logDirectoryPath;
ConfigurationDirectoryPath = configurationDirectoryPath;
CachePath = cacheDirectoryPath;
+
+ DataPath = Path.Combine(ProgramDataPath, "data");
}
+ ///
+ /// Gets the path to the program data folder
+ ///
+ /// The program data path.
public string ProgramDataPath { get; private set; }
///
/// Gets the path to the system folder
///
- public string ProgramSystemPath { get; private set; }
+ public string ProgramSystemPath { get; } = AppContext.BaseDirectory;
- ///
- /// The _data directory
- ///
- private string _dataDirectory;
///
/// Gets the folder path to the data directory
///
/// The data directory.
+ private string _dataPath;
public string DataPath
{
- get
- {
- if (_dataDirectory == null)
- {
- _dataDirectory = Path.Combine(ProgramDataPath, "data");
-
- Directory.CreateDirectory(_dataDirectory);
- }
-
- return _dataDirectory;
- }
+ get => _dataPath;
+ private set => _dataPath = Directory.CreateDirectory(value).FullName;
}
- private const string _virtualDataPath = "%AppDataPath%";
- public string VirtualDataPath => _virtualDataPath;
+ ///
+ /// Gets the magic strings used for virtual path manipulation.
+ ///
+ public string VirtualDataPath { get; } = "%AppDataPath%";
///
/// Gets the image cache path.
@@ -83,55 +78,17 @@ namespace Emby.Server.Implementations.AppBase
/// The plugin configurations path.
public string TempUpdatePath => Path.Combine(ProgramDataPath, "updates");
- ///
- /// The _log directory
- ///
- private string _logDirectoryPath;
-
///
/// Gets the path to the log directory
///
/// The log directory path.
- public string LogDirectoryPath
- {
- get
- {
- if (string.IsNullOrEmpty(_logDirectoryPath))
- {
- _logDirectoryPath = Path.Combine(ProgramDataPath, "logs");
-
- Directory.CreateDirectory(_logDirectoryPath);
- }
-
- return _logDirectoryPath;
- }
- set => _logDirectoryPath = value;
- }
-
- ///
- /// The _config directory
- ///
- private string _configurationDirectoryPath;
+ public string LogDirectoryPath { get; private set; }
///
/// Gets the path to the application configuration root directory
///
/// The configuration directory path.
- public string ConfigurationDirectoryPath
- {
- get
- {
- if (string.IsNullOrEmpty(_configurationDirectoryPath))
- {
- _configurationDirectoryPath = Path.Combine(ProgramDataPath, "config");
-
- Directory.CreateDirectory(_configurationDirectoryPath);
- }
-
- return _configurationDirectoryPath;
- }
- set => _configurationDirectoryPath = value;
- }
+ public string ConfigurationDirectoryPath { get; private set; }
///
/// Gets the path to the system configuration file
@@ -139,29 +96,11 @@ namespace Emby.Server.Implementations.AppBase
/// The system configuration file path.
public string SystemConfigurationFilePath => Path.Combine(ConfigurationDirectoryPath, "system.xml");
- ///
- /// The _cache directory
- ///
- private string _cachePath;
///
/// Gets the folder path to the cache directory
///
/// The cache directory.
- public string CachePath
- {
- get
- {
- if (string.IsNullOrEmpty(_cachePath))
- {
- _cachePath = Path.Combine(ProgramDataPath, "cache");
-
- Directory.CreateDirectory(_cachePath);
- }
-
- return _cachePath;
- }
- set => _cachePath = value;
- }
+ public string CachePath { get; set; }
///
/// Gets the folder path to the temp directory within the cache folder
diff --git a/Emby.Server.Implementations/ServerApplicationPaths.cs b/Emby.Server.Implementations/ServerApplicationPaths.cs
index 36975df50..05f6469ec 100644
--- a/Emby.Server.Implementations/ServerApplicationPaths.cs
+++ b/Emby.Server.Implementations/ServerApplicationPaths.cs
@@ -15,21 +15,17 @@ namespace Emby.Server.Implementations
///
public ServerApplicationPaths(
string programDataPath,
- string appFolderPath,
- string applicationResourcesPath,
- string logDirectoryPath = null,
- string configurationDirectoryPath = null,
- string cacheDirectoryPath = null)
+ string logDirectoryPath,
+ string configurationDirectoryPath,
+ string cacheDirectoryPath)
: base(programDataPath,
- appFolderPath,
logDirectoryPath,
configurationDirectoryPath,
cacheDirectoryPath)
{
- ApplicationResourcesPath = applicationResourcesPath;
}
- public string ApplicationResourcesPath { get; private set; }
+ public string ApplicationResourcesPath { get; } = AppContext.BaseDirectory;
///
/// Gets the path to the base root media directory
@@ -148,7 +144,6 @@ namespace Emby.Server.Implementations
set => _internalMetadataPath = value;
}
- private const string _virtualInternalMetadataPath = "%MetadataPath%";
- public string VirtualInternalMetadataPath => _virtualInternalMetadataPath;
+ public string VirtualInternalMetadataPath { get; } = "%MetadataPath%";
}
}
diff --git a/Jellyfin.Server/Program.cs b/Jellyfin.Server/Program.cs
index 7826fde35..6d372c36f 100644
--- a/Jellyfin.Server/Program.cs
+++ b/Jellyfin.Server/Program.cs
@@ -139,112 +139,156 @@ namespace Jellyfin.Server
}
}
+ ///
+ /// Create the data, config and log paths from the variety of inputs(command line args,
+ /// environment variables) or decide on what default to use. For Windows it's %AppPath%
+ /// for everything else the XDG approach is followed:
+ /// https://specifications.freedesktop.org/basedir-spec/basedir-spec-latest.html
+ ///
+ ///
+ /// ServerApplicationPaths
private static ServerApplicationPaths CreateApplicationPaths(StartupOptions options)
{
- string programDataPath = Environment.GetEnvironmentVariable("JELLYFIN_DATA_PATH");
- if (string.IsNullOrEmpty(programDataPath))
+ // dataDir
+ // IF --datadir
+ // ELSE IF $JELLYFIN_DATA_PATH
+ // ELSE IF windows, use <%APPDATA%>/jellyfin
+ // ELSE IF $XDG_DATA_HOME then use $XDG_DATA_HOME/jellyfin
+ // ELSE use $HOME/.local/share/jellyfin
+ var dataDir = options.DataDir;
+
+ if (string.IsNullOrEmpty(dataDir))
{
- if (options.DataDir != null)
- {
- programDataPath = options.DataDir;
- }
- else
+ dataDir = Environment.GetEnvironmentVariable("JELLYFIN_DATA_PATH");
+
+ if (string.IsNullOrEmpty(dataDir))
{
if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
{
- programDataPath = Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData);
+ dataDir = Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData);
}
else
{
// $XDG_DATA_HOME defines the base directory relative to which user specific data files should be stored.
- programDataPath = Environment.GetEnvironmentVariable("XDG_DATA_HOME");
- // If $XDG_DATA_HOME is either not set or empty, $HOME/.local/share should be used.
- if (string.IsNullOrEmpty(programDataPath))
+ dataDir = Environment.GetEnvironmentVariable("XDG_DATA_HOME");
+
+ // If $XDG_DATA_HOME is either not set or empty, a default equal to $HOME/.local/share should be used.
+ if (string.IsNullOrEmpty(dataDir))
{
- programDataPath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.UserProfile), ".local", "share");
+ dataDir = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.UserProfile), ".local", "share");
}
}
- programDataPath = Path.Combine(programDataPath, "jellyfin");
+ dataDir = Path.Combine(dataDir, "jellyfin");
}
}
- if (string.IsNullOrEmpty(programDataPath))
- {
- Console.WriteLine("Cannot continue without path to program data folder (try -programdata)");
- Environment.Exit(1);
- }
- else
- {
- Directory.CreateDirectory(programDataPath);
- }
+ // configDir
+ // IF --configdir
+ // ELSE IF $JELLYFIN_CONFIG_DIR
+ // ELSE IF --datadir, use /config (assume portable run)
+ // ELSE IF /config exists, use that
+ // ELSE IF windows, use /config
+ // ELSE IF $XDG_CONFIG_HOME use $XDG_CONFIG_HOME/jellyfin
+ // ELSE $HOME/.config/jellyfin
+ var configDir = options.ConfigDir;
- string configDir = Environment.GetEnvironmentVariable("JELLYFIN_CONFIG_DIR");
if (string.IsNullOrEmpty(configDir))
{
- if (options.ConfigDir != null)
+ configDir = Environment.GetEnvironmentVariable("JELLYFIN_CONFIG_DIR");
+
+ if (string.IsNullOrEmpty(configDir))
{
- configDir = options.ConfigDir;
- }
- else
- {
- // Let BaseApplicationPaths set up the default value
- configDir = null;
+ if (options.DataDir != null || Directory.Exists(Path.Combine(dataDir, "config")) || RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
+ {
+ // Hang config folder off already set dataDir
+ configDir = Path.Combine(dataDir, "config");
+ }
+ else
+ {
+ // $XDG_CONFIG_HOME defines the base directory relative to which user specific configuration files should be stored.
+ configDir = Environment.GetEnvironmentVariable("XDG_CONFIG_HOME");
+
+ // If $XDG_CONFIG_HOME is either not set or empty, a default equal to $HOME /.config should be used.
+ if (string.IsNullOrEmpty(configDir))
+ {
+ configDir = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.UserProfile), ".config");
+ }
+
+ configDir = Path.Combine(configDir, "jellyfin");
+ }
}
}
- if (configDir != null)
- {
- Directory.CreateDirectory(configDir);
- }
+ // cacheDir
+ // IF --cachedir
+ // ELSE IF $JELLYFIN_CACHE_DIR
+ // ELSE IF windows, use /cache
+ // ELSE IF XDG_CACHE_HOME, use $XDG_CACHE_HOME/jellyfin
+ // ELSE HOME/.cache/jellyfin
+ var cacheDir = options.CacheDir;
- string cacheDir = Environment.GetEnvironmentVariable("JELLYFIN_CACHE_DIR");
if (string.IsNullOrEmpty(cacheDir))
{
- if (options.CacheDir != null)
+ cacheDir = Environment.GetEnvironmentVariable("JELLYFIN_CACHE_DIR");
+
+ if (string.IsNullOrEmpty(cacheDir))
{
- cacheDir = options.CacheDir;
- }
- else if (!RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
- {
- // $XDG_CACHE_HOME defines the base directory relative to which user specific non-essential data files should be stored.
- cacheDir = Environment.GetEnvironmentVariable("XDG_CACHE_HOME");
- // If $XDG_CACHE_HOME is either not set or empty, $HOME/.cache should be used.
- if (string.IsNullOrEmpty(cacheDir))
+ if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
{
- cacheDir = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.UserProfile), ".cache");
+ // Hang cache folder off already set dataDir
+ cacheDir = Path.Combine(dataDir, "cache");
+ }
+ else
+ {
+ // $XDG_CACHE_HOME defines the base directory relative to which user specific non-essential data files should be stored.
+ cacheDir = Environment.GetEnvironmentVariable("XDG_CACHE_HOME");
+
+ // If $XDG_CACHE_HOME is either not set or empty, a default equal to $HOME/.cache should be used.
+ if (string.IsNullOrEmpty(cacheDir))
+ {
+ cacheDir = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.UserProfile), ".cache");
+ }
+
+ cacheDir = Path.Combine(cacheDir, "jellyfin");
}
- cacheDir = Path.Combine(cacheDir, "jellyfin");
}
}
- if (cacheDir != null)
- {
- Directory.CreateDirectory(cacheDir);
- }
+ // logDir
+ // IF --logdir
+ // ELSE IF $JELLYFIN_LOG_DIR
+ // ELSE IF --datadir, use /log (assume portable run)
+ // ELSE /log
+ var logDir = options.LogDir;
- string logDir = Environment.GetEnvironmentVariable("JELLYFIN_LOG_DIR");
if (string.IsNullOrEmpty(logDir))
{
- if (options.LogDir != null)
+ logDir = Environment.GetEnvironmentVariable("JELLYFIN_LOG_DIR");
+
+ if (string.IsNullOrEmpty(logDir))
{
- logDir = options.LogDir;
- }
- else
- {
- // Let BaseApplicationPaths set up the default value
- logDir = null;
+ // Hang log folder off already set dataDir
+ logDir = Path.Combine(dataDir, "log");
}
}
- if (logDir != null)
+ // Ensure the main folders exist before we continue
+ try
{
+ Directory.CreateDirectory(dataDir);
Directory.CreateDirectory(logDir);
+ Directory.CreateDirectory(configDir);
+ Directory.CreateDirectory(cacheDir);
+ }
+ catch (IOException ex)
+ {
+ Console.Error.WriteLine("Error whilst attempting to create folder");
+ Console.Error.WriteLine(ex.ToString());
+ Environment.Exit(1);
}
- string appPath = AppContext.BaseDirectory;
-
- return new ServerApplicationPaths(programDataPath, appPath, appPath, logDir, configDir, cacheDir);
+ return new ServerApplicationPaths(dataDir, logDir, configDir, cacheDir);
}
private static async Task CreateLogger(IApplicationPaths appPaths)