using System; using System.Collections.Generic; using System.IO; using System.Linq; using Jellyfin.Extensions; using MediaBrowser.Common.Configuration; namespace Emby.Server.Implementations.AppBase { /// /// Provides a base class to hold common application paths used by both the UI and Server. /// This can be subclassed to add application-specific paths. /// public abstract class BaseApplicationPaths : IApplicationPaths { /// /// Initializes a new instance of the class. /// /// The program data path. /// The log directory path. /// The configuration directory path. /// The cache directory path. /// The web directory path. protected BaseApplicationPaths( string programDataPath, string logDirectoryPath, string configurationDirectoryPath, string cacheDirectoryPath, string webDirectoryPath) { ProgramDataPath = programDataPath; LogDirectoryPath = logDirectoryPath; ConfigurationDirectoryPath = configurationDirectoryPath; CachePath = cacheDirectoryPath; WebPath = webDirectoryPath; DataPath = Directory.CreateDirectory(Path.Combine(ProgramDataPath, "data")).FullName; } /// public string ProgramDataPath { get; } /// public string WebPath { get; } /// public string ProgramSystemPath { get; } = AppContext.BaseDirectory; /// public string DataPath { get; } /// public string VirtualDataPath => "%AppDataPath%"; /// public string ImageCachePath => Path.Combine(CachePath, "images"); /// public string PluginsPath => Path.Combine(ProgramDataPath, "plugins"); /// public string PluginConfigurationsPath => Path.Combine(PluginsPath, "configurations"); /// public string LogDirectoryPath { get; } /// public string ConfigurationDirectoryPath { get; } /// public string SystemConfigurationFilePath => Path.Combine(ConfigurationDirectoryPath, "system.xml"); /// public string CachePath { get; set; } /// public string TempDirectory => Path.Join(Path.GetTempPath(), "jellyfin"); /// public string TrickplayPath => Path.Combine(DataPath, "trickplay"); /// public string BackupPath => Path.Combine(DataPath, "backups"); /// public virtual void MakeSanityCheckOrThrow() { CreateAndCheckMarker(ConfigurationDirectoryPath, "config"); CreateAndCheckMarker(LogDirectoryPath, "log"); CreateAndCheckMarker(PluginsPath, "plugin"); CreateAndCheckMarker(ProgramDataPath, "data"); CreateAndCheckMarker(CachePath, "cache"); CreateAndCheckMarker(DataPath, "data"); } /// public void CreateAndCheckMarker(string path, string markerName, bool recursive = false) { Directory.CreateDirectory(path); CheckOrCreateMarker(path, $".jellyfin-{markerName}", recursive); } private IEnumerable GetMarkers(string path, bool recursive = false) { return Directory.EnumerateFiles(path, ".jellyfin-*", recursive ? SearchOption.AllDirectories : SearchOption.TopDirectoryOnly); } private void CheckOrCreateMarker(string path, string markerName, bool recursive = false) { var otherMarkers = GetMarkers(path, recursive).FirstOrDefault(e => Path.GetFileName(e) != markerName); if (otherMarkers != null) { throw new InvalidOperationException($"Exepected to find only {markerName} but found marker for {otherMarkers}."); } var markerPath = Path.Combine(path, markerName); if (!File.Exists(markerPath)) { FileHelper.CreateEmpty(markerPath); } } } }