mirror of
https://github.com/jellyfin/jellyfin.git
synced 2026-04-22 10:04:44 +01:00
make more classes portable
This commit is contained in:
178
Emby.Server.Implementations/AppBase/BaseApplicationPaths.cs
Normal file
178
Emby.Server.Implementations/AppBase/BaseApplicationPaths.cs
Normal file
@@ -0,0 +1,178 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
using MediaBrowser.Common.Configuration;
|
||||
|
||||
namespace Emby.Server.Implementations.AppBase
|
||||
{
|
||||
/// <summary>
|
||||
/// 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.
|
||||
/// </summary>
|
||||
public abstract class BaseApplicationPaths : IApplicationPaths
|
||||
{
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="BaseApplicationPaths"/> class.
|
||||
/// </summary>
|
||||
protected BaseApplicationPaths(string programDataPath, string appFolderPath, Action<string> createDirectoryFn)
|
||||
{
|
||||
ProgramDataPath = programDataPath;
|
||||
ProgramSystemPath = appFolderPath;
|
||||
CreateDirectoryFn = createDirectoryFn;
|
||||
}
|
||||
|
||||
protected Action<string> CreateDirectoryFn;
|
||||
|
||||
public string ProgramDataPath { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the path to the system folder
|
||||
/// </summary>
|
||||
public string ProgramSystemPath { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// The _data directory
|
||||
/// </summary>
|
||||
private string _dataDirectory;
|
||||
/// <summary>
|
||||
/// Gets the folder path to the data directory
|
||||
/// </summary>
|
||||
/// <value>The data directory.</value>
|
||||
public string DataPath
|
||||
{
|
||||
get
|
||||
{
|
||||
if (_dataDirectory == null)
|
||||
{
|
||||
_dataDirectory = Path.Combine(ProgramDataPath, "data");
|
||||
|
||||
CreateDirectoryFn(_dataDirectory);
|
||||
}
|
||||
|
||||
return _dataDirectory;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the image cache path.
|
||||
/// </summary>
|
||||
/// <value>The image cache path.</value>
|
||||
public string ImageCachePath
|
||||
{
|
||||
get
|
||||
{
|
||||
return Path.Combine(CachePath, "images");
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the path to the plugin directory
|
||||
/// </summary>
|
||||
/// <value>The plugins path.</value>
|
||||
public string PluginsPath
|
||||
{
|
||||
get
|
||||
{
|
||||
return Path.Combine(ProgramDataPath, "plugins");
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the path to the plugin configurations directory
|
||||
/// </summary>
|
||||
/// <value>The plugin configurations path.</value>
|
||||
public string PluginConfigurationsPath
|
||||
{
|
||||
get
|
||||
{
|
||||
return Path.Combine(PluginsPath, "configurations");
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the path to where temporary update files will be stored
|
||||
/// </summary>
|
||||
/// <value>The plugin configurations path.</value>
|
||||
public string TempUpdatePath
|
||||
{
|
||||
get
|
||||
{
|
||||
return Path.Combine(ProgramDataPath, "updates");
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the path to the log directory
|
||||
/// </summary>
|
||||
/// <value>The log directory path.</value>
|
||||
public string LogDirectoryPath
|
||||
{
|
||||
get
|
||||
{
|
||||
return Path.Combine(ProgramDataPath, "logs");
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the path to the application configuration root directory
|
||||
/// </summary>
|
||||
/// <value>The configuration directory path.</value>
|
||||
public string ConfigurationDirectoryPath
|
||||
{
|
||||
get
|
||||
{
|
||||
return Path.Combine(ProgramDataPath, "config");
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the path to the system configuration file
|
||||
/// </summary>
|
||||
/// <value>The system configuration file path.</value>
|
||||
public string SystemConfigurationFilePath
|
||||
{
|
||||
get
|
||||
{
|
||||
return Path.Combine(ConfigurationDirectoryPath, "system.xml");
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The _cache directory
|
||||
/// </summary>
|
||||
private string _cachePath;
|
||||
/// <summary>
|
||||
/// Gets the folder path to the cache directory
|
||||
/// </summary>
|
||||
/// <value>The cache directory.</value>
|
||||
public string CachePath
|
||||
{
|
||||
get
|
||||
{
|
||||
if (string.IsNullOrEmpty(_cachePath))
|
||||
{
|
||||
_cachePath = Path.Combine(ProgramDataPath, "cache");
|
||||
|
||||
CreateDirectoryFn(_cachePath);
|
||||
}
|
||||
|
||||
return _cachePath;
|
||||
}
|
||||
set
|
||||
{
|
||||
_cachePath = value;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the folder path to the temp directory within the cache folder
|
||||
/// </summary>
|
||||
/// <value>The temp directory.</value>
|
||||
public string TempDirectory
|
||||
{
|
||||
get
|
||||
{
|
||||
return Path.Combine(CachePath, "temp");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
328
Emby.Server.Implementations/AppBase/BaseConfigurationManager.cs
Normal file
328
Emby.Server.Implementations/AppBase/BaseConfigurationManager.cs
Normal file
@@ -0,0 +1,328 @@
|
||||
using System;
|
||||
using System.Collections.Concurrent;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Threading;
|
||||
using MediaBrowser.Common.Configuration;
|
||||
using MediaBrowser.Common.Events;
|
||||
using MediaBrowser.Common.Extensions;
|
||||
using MediaBrowser.Model.Configuration;
|
||||
using MediaBrowser.Model.IO;
|
||||
using MediaBrowser.Model.Logging;
|
||||
using MediaBrowser.Model.Serialization;
|
||||
|
||||
namespace Emby.Server.Implementations.AppBase
|
||||
{
|
||||
/// <summary>
|
||||
/// Class BaseConfigurationManager
|
||||
/// </summary>
|
||||
public abstract class BaseConfigurationManager : IConfigurationManager
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets the type of the configuration.
|
||||
/// </summary>
|
||||
/// <value>The type of the configuration.</value>
|
||||
protected abstract Type ConfigurationType { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Occurs when [configuration updated].
|
||||
/// </summary>
|
||||
public event EventHandler<EventArgs> ConfigurationUpdated;
|
||||
|
||||
/// <summary>
|
||||
/// Occurs when [configuration updating].
|
||||
/// </summary>
|
||||
public event EventHandler<ConfigurationUpdateEventArgs> NamedConfigurationUpdating;
|
||||
|
||||
/// <summary>
|
||||
/// Occurs when [named configuration updated].
|
||||
/// </summary>
|
||||
public event EventHandler<ConfigurationUpdateEventArgs> NamedConfigurationUpdated;
|
||||
|
||||
/// <summary>
|
||||
/// Gets the logger.
|
||||
/// </summary>
|
||||
/// <value>The logger.</value>
|
||||
protected ILogger Logger { get; private set; }
|
||||
/// <summary>
|
||||
/// Gets the XML serializer.
|
||||
/// </summary>
|
||||
/// <value>The XML serializer.</value>
|
||||
protected IXmlSerializer XmlSerializer { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the application paths.
|
||||
/// </summary>
|
||||
/// <value>The application paths.</value>
|
||||
public IApplicationPaths CommonApplicationPaths { get; private set; }
|
||||
public readonly IFileSystem FileSystem;
|
||||
|
||||
/// <summary>
|
||||
/// The _configuration loaded
|
||||
/// </summary>
|
||||
private bool _configurationLoaded;
|
||||
/// <summary>
|
||||
/// The _configuration sync lock
|
||||
/// </summary>
|
||||
private object _configurationSyncLock = new object();
|
||||
/// <summary>
|
||||
/// The _configuration
|
||||
/// </summary>
|
||||
private BaseApplicationConfiguration _configuration;
|
||||
/// <summary>
|
||||
/// Gets the system configuration
|
||||
/// </summary>
|
||||
/// <value>The configuration.</value>
|
||||
public BaseApplicationConfiguration CommonConfiguration
|
||||
{
|
||||
get
|
||||
{
|
||||
// Lazy load
|
||||
LazyInitializer.EnsureInitialized(ref _configuration, ref _configurationLoaded, ref _configurationSyncLock, () => (BaseApplicationConfiguration)ConfigurationHelper.GetXmlConfiguration(ConfigurationType, CommonApplicationPaths.SystemConfigurationFilePath, XmlSerializer, FileSystem));
|
||||
return _configuration;
|
||||
}
|
||||
protected set
|
||||
{
|
||||
_configuration = value;
|
||||
|
||||
_configurationLoaded = value != null;
|
||||
}
|
||||
}
|
||||
|
||||
private ConfigurationStore[] _configurationStores = { };
|
||||
private IConfigurationFactory[] _configurationFactories = { };
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="BaseConfigurationManager" /> class.
|
||||
/// </summary>
|
||||
/// <param name="applicationPaths">The application paths.</param>
|
||||
/// <param name="logManager">The log manager.</param>
|
||||
/// <param name="xmlSerializer">The XML serializer.</param>
|
||||
protected BaseConfigurationManager(IApplicationPaths applicationPaths, ILogManager logManager, IXmlSerializer xmlSerializer, IFileSystem fileSystem)
|
||||
{
|
||||
CommonApplicationPaths = applicationPaths;
|
||||
XmlSerializer = xmlSerializer;
|
||||
FileSystem = fileSystem;
|
||||
Logger = logManager.GetLogger(GetType().Name);
|
||||
|
||||
UpdateCachePath();
|
||||
}
|
||||
|
||||
public virtual void AddParts(IEnumerable<IConfigurationFactory> factories)
|
||||
{
|
||||
_configurationFactories = factories.ToArray();
|
||||
|
||||
_configurationStores = _configurationFactories
|
||||
.SelectMany(i => i.GetConfigurations())
|
||||
.ToArray();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Saves the configuration.
|
||||
/// </summary>
|
||||
public void SaveConfiguration()
|
||||
{
|
||||
Logger.Info("Saving system configuration");
|
||||
var path = CommonApplicationPaths.SystemConfigurationFilePath;
|
||||
|
||||
FileSystem.CreateDirectory(Path.GetDirectoryName(path));
|
||||
|
||||
lock (_configurationSyncLock)
|
||||
{
|
||||
XmlSerializer.SerializeToFile(CommonConfiguration, path);
|
||||
}
|
||||
|
||||
OnConfigurationUpdated();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Called when [configuration updated].
|
||||
/// </summary>
|
||||
protected virtual void OnConfigurationUpdated()
|
||||
{
|
||||
UpdateCachePath();
|
||||
|
||||
EventHelper.QueueEventIfNotNull(ConfigurationUpdated, this, EventArgs.Empty, Logger);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Replaces the configuration.
|
||||
/// </summary>
|
||||
/// <param name="newConfiguration">The new configuration.</param>
|
||||
/// <exception cref="System.ArgumentNullException">newConfiguration</exception>
|
||||
public virtual void ReplaceConfiguration(BaseApplicationConfiguration newConfiguration)
|
||||
{
|
||||
if (newConfiguration == null)
|
||||
{
|
||||
throw new ArgumentNullException("newConfiguration");
|
||||
}
|
||||
|
||||
ValidateCachePath(newConfiguration);
|
||||
|
||||
CommonConfiguration = newConfiguration;
|
||||
SaveConfiguration();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Updates the items by name path.
|
||||
/// </summary>
|
||||
private void UpdateCachePath()
|
||||
{
|
||||
string cachePath;
|
||||
|
||||
if (string.IsNullOrWhiteSpace(CommonConfiguration.CachePath))
|
||||
{
|
||||
cachePath = null;
|
||||
}
|
||||
else
|
||||
{
|
||||
cachePath = Path.Combine(CommonConfiguration.CachePath, "cache");
|
||||
}
|
||||
|
||||
((BaseApplicationPaths)CommonApplicationPaths).CachePath = cachePath;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Replaces the cache path.
|
||||
/// </summary>
|
||||
/// <param name="newConfig">The new configuration.</param>
|
||||
/// <exception cref="System.IO.DirectoryNotFoundException"></exception>
|
||||
private void ValidateCachePath(BaseApplicationConfiguration newConfig)
|
||||
{
|
||||
var newPath = newConfig.CachePath;
|
||||
|
||||
if (!string.IsNullOrWhiteSpace(newPath)
|
||||
&& !string.Equals(CommonConfiguration.CachePath ?? string.Empty, newPath))
|
||||
{
|
||||
// Validate
|
||||
if (!FileSystem.DirectoryExists(newPath))
|
||||
{
|
||||
throw new FileNotFoundException(string.Format("{0} does not exist.", newPath));
|
||||
}
|
||||
|
||||
EnsureWriteAccess(newPath);
|
||||
}
|
||||
}
|
||||
|
||||
protected void EnsureWriteAccess(string path)
|
||||
{
|
||||
var file = Path.Combine(path, Guid.NewGuid().ToString());
|
||||
|
||||
FileSystem.WriteAllText(file, string.Empty);
|
||||
FileSystem.DeleteFile(file);
|
||||
}
|
||||
|
||||
private readonly ConcurrentDictionary<string, object> _configurations = new ConcurrentDictionary<string, object>();
|
||||
|
||||
private string GetConfigurationFile(string key)
|
||||
{
|
||||
return Path.Combine(CommonApplicationPaths.ConfigurationDirectoryPath, key.ToLower() + ".xml");
|
||||
}
|
||||
|
||||
public object GetConfiguration(string key)
|
||||
{
|
||||
return _configurations.GetOrAdd(key, k =>
|
||||
{
|
||||
var file = GetConfigurationFile(key);
|
||||
|
||||
var configurationInfo = _configurationStores
|
||||
.FirstOrDefault(i => string.Equals(i.Key, key, StringComparison.OrdinalIgnoreCase));
|
||||
|
||||
if (configurationInfo == null)
|
||||
{
|
||||
throw new ResourceNotFoundException("Configuration with key " + key + " not found.");
|
||||
}
|
||||
|
||||
var configurationType = configurationInfo.ConfigurationType;
|
||||
|
||||
lock (_configurationSyncLock)
|
||||
{
|
||||
return LoadConfiguration(file, configurationType);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private object LoadConfiguration(string path, Type configurationType)
|
||||
{
|
||||
try
|
||||
{
|
||||
return XmlSerializer.DeserializeFromFile(configurationType, path);
|
||||
}
|
||||
catch (FileNotFoundException)
|
||||
{
|
||||
return Activator.CreateInstance(configurationType);
|
||||
}
|
||||
catch (IOException)
|
||||
{
|
||||
return Activator.CreateInstance(configurationType);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Logger.ErrorException("Error loading configuration file: {0}", ex, path);
|
||||
|
||||
return Activator.CreateInstance(configurationType);
|
||||
}
|
||||
}
|
||||
|
||||
public void SaveConfiguration(string key, object configuration)
|
||||
{
|
||||
var configurationStore = GetConfigurationStore(key);
|
||||
var configurationType = configurationStore.ConfigurationType;
|
||||
|
||||
if (configuration.GetType() != configurationType)
|
||||
{
|
||||
throw new ArgumentException("Expected configuration type is " + configurationType.Name);
|
||||
}
|
||||
|
||||
var validatingStore = configurationStore as IValidatingConfiguration;
|
||||
if (validatingStore != null)
|
||||
{
|
||||
var currentConfiguration = GetConfiguration(key);
|
||||
|
||||
validatingStore.Validate(currentConfiguration, configuration);
|
||||
}
|
||||
|
||||
EventHelper.FireEventIfNotNull(NamedConfigurationUpdating, this, new ConfigurationUpdateEventArgs
|
||||
{
|
||||
Key = key,
|
||||
NewConfiguration = configuration
|
||||
|
||||
}, Logger);
|
||||
|
||||
_configurations.AddOrUpdate(key, configuration, (k, v) => configuration);
|
||||
|
||||
var path = GetConfigurationFile(key);
|
||||
FileSystem.CreateDirectory(Path.GetDirectoryName(path));
|
||||
|
||||
lock (_configurationSyncLock)
|
||||
{
|
||||
XmlSerializer.SerializeToFile(configuration, path);
|
||||
}
|
||||
|
||||
OnNamedConfigurationUpdated(key, configuration);
|
||||
}
|
||||
|
||||
protected virtual void OnNamedConfigurationUpdated(string key, object configuration)
|
||||
{
|
||||
EventHelper.FireEventIfNotNull(NamedConfigurationUpdated, this, new ConfigurationUpdateEventArgs
|
||||
{
|
||||
Key = key,
|
||||
NewConfiguration = configuration
|
||||
|
||||
}, Logger);
|
||||
}
|
||||
|
||||
public Type GetConfigurationType(string key)
|
||||
{
|
||||
return GetConfigurationStore(key)
|
||||
.ConfigurationType;
|
||||
}
|
||||
|
||||
private ConfigurationStore GetConfigurationStore(string key)
|
||||
{
|
||||
return _configurationStores
|
||||
.First(i => string.Equals(i.Key, key, StringComparison.OrdinalIgnoreCase));
|
||||
}
|
||||
}
|
||||
}
|
||||
60
Emby.Server.Implementations/AppBase/ConfigurationHelper.cs
Normal file
60
Emby.Server.Implementations/AppBase/ConfigurationHelper.cs
Normal file
@@ -0,0 +1,60 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using MediaBrowser.Model.IO;
|
||||
using MediaBrowser.Model.Serialization;
|
||||
|
||||
namespace Emby.Server.Implementations.AppBase
|
||||
{
|
||||
/// <summary>
|
||||
/// Class ConfigurationHelper
|
||||
/// </summary>
|
||||
public static class ConfigurationHelper
|
||||
{
|
||||
/// <summary>
|
||||
/// Reads an xml configuration file from the file system
|
||||
/// It will immediately re-serialize and save if new serialization data is available due to property changes
|
||||
/// </summary>
|
||||
/// <param name="type">The type.</param>
|
||||
/// <param name="path">The path.</param>
|
||||
/// <param name="xmlSerializer">The XML serializer.</param>
|
||||
/// <returns>System.Object.</returns>
|
||||
public static object GetXmlConfiguration(Type type, string path, IXmlSerializer xmlSerializer, IFileSystem fileSystem)
|
||||
{
|
||||
object configuration;
|
||||
|
||||
byte[] buffer = null;
|
||||
|
||||
// Use try/catch to avoid the extra file system lookup using File.Exists
|
||||
try
|
||||
{
|
||||
buffer = fileSystem.ReadAllBytes(path);
|
||||
|
||||
configuration = xmlSerializer.DeserializeFromBytes(type, buffer);
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
configuration = Activator.CreateInstance(type);
|
||||
}
|
||||
|
||||
using (var stream = new MemoryStream())
|
||||
{
|
||||
xmlSerializer.SerializeToStream(configuration, stream);
|
||||
|
||||
// Take the object we just got and serialize it back to bytes
|
||||
var newBytes = stream.ToArray();
|
||||
|
||||
// If the file didn't exist before, or if something has changed, re-save
|
||||
if (buffer == null || !buffer.SequenceEqual(newBytes))
|
||||
{
|
||||
fileSystem.CreateDirectory(Path.GetDirectoryName(path));
|
||||
|
||||
// Save it after load in case we got new items
|
||||
fileSystem.WriteAllBytes(path, newBytes);
|
||||
}
|
||||
|
||||
return configuration;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,245 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using Emby.Server.Implementations.AppBase;
|
||||
using MediaBrowser.Common.Configuration;
|
||||
using MediaBrowser.Common.Events;
|
||||
using MediaBrowser.Controller;
|
||||
using MediaBrowser.Controller.Configuration;
|
||||
using MediaBrowser.Controller.Entities;
|
||||
using MediaBrowser.Controller.Entities.Audio;
|
||||
using MediaBrowser.Controller.Entities.Movies;
|
||||
using MediaBrowser.Controller.Entities.TV;
|
||||
using MediaBrowser.Model.Configuration;
|
||||
using MediaBrowser.Model.Events;
|
||||
using MediaBrowser.Model.IO;
|
||||
using MediaBrowser.Model.Logging;
|
||||
using MediaBrowser.Model.Serialization;
|
||||
|
||||
namespace Emby.Server.Implementations.Configuration
|
||||
{
|
||||
/// <summary>
|
||||
/// Class ServerConfigurationManager
|
||||
/// </summary>
|
||||
public class ServerConfigurationManager : BaseConfigurationManager, IServerConfigurationManager
|
||||
{
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="ServerConfigurationManager" /> class.
|
||||
/// </summary>
|
||||
/// <param name="applicationPaths">The application paths.</param>
|
||||
/// <param name="logManager">The log manager.</param>
|
||||
/// <param name="xmlSerializer">The XML serializer.</param>
|
||||
/// <param name="fileSystem">The file system.</param>
|
||||
public ServerConfigurationManager(IApplicationPaths applicationPaths, ILogManager logManager, IXmlSerializer xmlSerializer, IFileSystem fileSystem)
|
||||
: base(applicationPaths, logManager, xmlSerializer, fileSystem)
|
||||
{
|
||||
UpdateMetadataPath();
|
||||
}
|
||||
|
||||
public event EventHandler<GenericEventArgs<ServerConfiguration>> ConfigurationUpdating;
|
||||
|
||||
/// <summary>
|
||||
/// Gets the type of the configuration.
|
||||
/// </summary>
|
||||
/// <value>The type of the configuration.</value>
|
||||
protected override Type ConfigurationType
|
||||
{
|
||||
get { return typeof(ServerConfiguration); }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the application paths.
|
||||
/// </summary>
|
||||
/// <value>The application paths.</value>
|
||||
public IServerApplicationPaths ApplicationPaths
|
||||
{
|
||||
get { return (IServerApplicationPaths)CommonApplicationPaths; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the configuration.
|
||||
/// </summary>
|
||||
/// <value>The configuration.</value>
|
||||
public ServerConfiguration Configuration
|
||||
{
|
||||
get { return (ServerConfiguration)CommonConfiguration; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Called when [configuration updated].
|
||||
/// </summary>
|
||||
protected override void OnConfigurationUpdated()
|
||||
{
|
||||
UpdateMetadataPath();
|
||||
|
||||
base.OnConfigurationUpdated();
|
||||
}
|
||||
|
||||
public override void AddParts(IEnumerable<IConfigurationFactory> factories)
|
||||
{
|
||||
base.AddParts(factories);
|
||||
|
||||
UpdateTranscodingTempPath();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Updates the metadata path.
|
||||
/// </summary>
|
||||
private void UpdateMetadataPath()
|
||||
{
|
||||
string metadataPath;
|
||||
|
||||
if (string.IsNullOrWhiteSpace(Configuration.MetadataPath))
|
||||
{
|
||||
metadataPath = GetInternalMetadataPath();
|
||||
}
|
||||
else
|
||||
{
|
||||
metadataPath = Path.Combine(Configuration.MetadataPath, "metadata");
|
||||
}
|
||||
|
||||
((ServerApplicationPaths)ApplicationPaths).InternalMetadataPath = metadataPath;
|
||||
|
||||
((ServerApplicationPaths)ApplicationPaths).ItemsByNamePath = ((ServerApplicationPaths)ApplicationPaths).InternalMetadataPath;
|
||||
}
|
||||
|
||||
private string GetInternalMetadataPath()
|
||||
{
|
||||
return Path.Combine(ApplicationPaths.ProgramDataPath, "metadata");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Updates the transcoding temporary path.
|
||||
/// </summary>
|
||||
private void UpdateTranscodingTempPath()
|
||||
{
|
||||
var encodingConfig = this.GetConfiguration<EncodingOptions>("encoding");
|
||||
|
||||
((ServerApplicationPaths)ApplicationPaths).TranscodingTempPath = string.IsNullOrEmpty(encodingConfig.TranscodingTempPath) ?
|
||||
null :
|
||||
Path.Combine(encodingConfig.TranscodingTempPath, "transcoding-temp");
|
||||
}
|
||||
|
||||
protected override void OnNamedConfigurationUpdated(string key, object configuration)
|
||||
{
|
||||
base.OnNamedConfigurationUpdated(key, configuration);
|
||||
|
||||
if (string.Equals(key, "encoding", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
UpdateTranscodingTempPath();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Replaces the configuration.
|
||||
/// </summary>
|
||||
/// <param name="newConfiguration">The new configuration.</param>
|
||||
/// <exception cref="System.IO.DirectoryNotFoundException"></exception>
|
||||
public override void ReplaceConfiguration(BaseApplicationConfiguration newConfiguration)
|
||||
{
|
||||
var newConfig = (ServerConfiguration)newConfiguration;
|
||||
|
||||
ValidateMetadataPath(newConfig);
|
||||
ValidateSslCertificate(newConfig);
|
||||
|
||||
EventHelper.FireEventIfNotNull(ConfigurationUpdating, this, new GenericEventArgs<ServerConfiguration> { Argument = newConfig }, Logger);
|
||||
|
||||
base.ReplaceConfiguration(newConfiguration);
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Validates the SSL certificate.
|
||||
/// </summary>
|
||||
/// <param name="newConfig">The new configuration.</param>
|
||||
/// <exception cref="System.IO.DirectoryNotFoundException"></exception>
|
||||
private void ValidateSslCertificate(BaseApplicationConfiguration newConfig)
|
||||
{
|
||||
var serverConfig = (ServerConfiguration)newConfig;
|
||||
|
||||
var newPath = serverConfig.CertificatePath;
|
||||
|
||||
if (!string.IsNullOrWhiteSpace(newPath)
|
||||
&& !string.Equals(Configuration.CertificatePath ?? string.Empty, newPath))
|
||||
{
|
||||
// Validate
|
||||
if (!FileSystem.FileExists(newPath))
|
||||
{
|
||||
throw new FileNotFoundException(string.Format("Certificate file '{0}' does not exist.", newPath));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Validates the metadata path.
|
||||
/// </summary>
|
||||
/// <param name="newConfig">The new configuration.</param>
|
||||
/// <exception cref="System.IO.DirectoryNotFoundException"></exception>
|
||||
private void ValidateMetadataPath(ServerConfiguration newConfig)
|
||||
{
|
||||
var newPath = newConfig.MetadataPath;
|
||||
|
||||
if (!string.IsNullOrWhiteSpace(newPath)
|
||||
&& !string.Equals(Configuration.MetadataPath ?? string.Empty, newPath))
|
||||
{
|
||||
// Validate
|
||||
if (!FileSystem.DirectoryExists(newPath))
|
||||
{
|
||||
throw new FileNotFoundException(string.Format("{0} does not exist.", newPath));
|
||||
}
|
||||
|
||||
EnsureWriteAccess(newPath);
|
||||
}
|
||||
}
|
||||
|
||||
public void DisableMetadataService(string service)
|
||||
{
|
||||
DisableMetadataService(typeof(Movie), Configuration, service);
|
||||
DisableMetadataService(typeof(Episode), Configuration, service);
|
||||
DisableMetadataService(typeof(Series), Configuration, service);
|
||||
DisableMetadataService(typeof(Season), Configuration, service);
|
||||
DisableMetadataService(typeof(MusicArtist), Configuration, service);
|
||||
DisableMetadataService(typeof(MusicAlbum), Configuration, service);
|
||||
DisableMetadataService(typeof(MusicVideo), Configuration, service);
|
||||
DisableMetadataService(typeof(Video), Configuration, service);
|
||||
}
|
||||
|
||||
private void DisableMetadataService(Type type, ServerConfiguration config, string service)
|
||||
{
|
||||
var options = GetMetadataOptions(type, config);
|
||||
|
||||
if (!options.DisabledMetadataSavers.Contains(service, StringComparer.OrdinalIgnoreCase))
|
||||
{
|
||||
var list = options.DisabledMetadataSavers.ToList();
|
||||
|
||||
list.Add(service);
|
||||
|
||||
options.DisabledMetadataSavers = list.ToArray();
|
||||
}
|
||||
}
|
||||
|
||||
private MetadataOptions GetMetadataOptions(Type type, ServerConfiguration config)
|
||||
{
|
||||
var options = config.MetadataOptions
|
||||
.FirstOrDefault(i => string.Equals(i.ItemType, type.Name, StringComparison.OrdinalIgnoreCase));
|
||||
|
||||
if (options == null)
|
||||
{
|
||||
var list = config.MetadataOptions.ToList();
|
||||
|
||||
options = new MetadataOptions
|
||||
{
|
||||
ItemType = type.Name
|
||||
};
|
||||
|
||||
list.Add(options);
|
||||
|
||||
config.MetadataOptions = list.ToArray();
|
||||
}
|
||||
|
||||
return options;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,36 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Emby.Server.Implementations.Connect
|
||||
{
|
||||
public class ConnectData
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets or sets the server identifier.
|
||||
/// </summary>
|
||||
/// <value>The server identifier.</value>
|
||||
public string ServerId { get; set; }
|
||||
/// <summary>
|
||||
/// Gets or sets the access key.
|
||||
/// </summary>
|
||||
/// <value>The access key.</value>
|
||||
public string AccessKey { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the authorizations.
|
||||
/// </summary>
|
||||
/// <value>The authorizations.</value>
|
||||
public List<ConnectAuthorizationInternal> PendingAuthorizations { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the last authorizations refresh.
|
||||
/// </summary>
|
||||
/// <value>The last authorizations refresh.</value>
|
||||
public DateTime LastAuthorizationsRefresh { get; set; }
|
||||
|
||||
public ConnectData()
|
||||
{
|
||||
PendingAuthorizations = new List<ConnectAuthorizationInternal>();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,218 +0,0 @@
|
||||
using MediaBrowser.Common;
|
||||
using MediaBrowser.Common.Configuration;
|
||||
using MediaBrowser.Common.Net;
|
||||
using MediaBrowser.Controller.Connect;
|
||||
using MediaBrowser.Controller.Plugins;
|
||||
using MediaBrowser.Model.Logging;
|
||||
using MediaBrowser.Model.Net;
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using MediaBrowser.Controller.Security;
|
||||
using MediaBrowser.Model.IO;
|
||||
using MediaBrowser.Model.Threading;
|
||||
|
||||
namespace Emby.Server.Implementations.Connect
|
||||
{
|
||||
public class ConnectEntryPoint : IServerEntryPoint
|
||||
{
|
||||
private ITimer _timer;
|
||||
private IpAddressInfo _cachedIpAddress;
|
||||
private readonly IHttpClient _httpClient;
|
||||
private readonly IApplicationPaths _appPaths;
|
||||
private readonly ILogger _logger;
|
||||
private readonly IConnectManager _connectManager;
|
||||
|
||||
private readonly INetworkManager _networkManager;
|
||||
private readonly IApplicationHost _appHost;
|
||||
private readonly IFileSystem _fileSystem;
|
||||
private readonly ITimerFactory _timerFactory;
|
||||
private readonly IEncryptionManager _encryption;
|
||||
|
||||
public ConnectEntryPoint(IHttpClient httpClient, IApplicationPaths appPaths, ILogger logger, INetworkManager networkManager, IConnectManager connectManager, IApplicationHost appHost, IFileSystem fileSystem, ITimerFactory timerFactory, IEncryptionManager encryption)
|
||||
{
|
||||
_httpClient = httpClient;
|
||||
_appPaths = appPaths;
|
||||
_logger = logger;
|
||||
_networkManager = networkManager;
|
||||
_connectManager = connectManager;
|
||||
_appHost = appHost;
|
||||
_fileSystem = fileSystem;
|
||||
_timerFactory = timerFactory;
|
||||
_encryption = encryption;
|
||||
}
|
||||
|
||||
public void Run()
|
||||
{
|
||||
LoadCachedAddress();
|
||||
|
||||
_timer = _timerFactory.Create(TimerCallback, null, TimeSpan.FromSeconds(5), TimeSpan.FromHours(1));
|
||||
((ConnectManager)_connectManager).Start();
|
||||
}
|
||||
|
||||
private readonly string[] _ipLookups =
|
||||
{
|
||||
"http://bot.whatismyipaddress.com",
|
||||
"https://connect.emby.media/service/ip"
|
||||
};
|
||||
|
||||
private async void TimerCallback(object state)
|
||||
{
|
||||
IpAddressInfo validIpAddress = null;
|
||||
|
||||
foreach (var ipLookupUrl in _ipLookups)
|
||||
{
|
||||
try
|
||||
{
|
||||
validIpAddress = await GetIpAddress(ipLookupUrl).ConfigureAwait(false);
|
||||
|
||||
// Try to find the ipv4 address, if present
|
||||
if (validIpAddress.AddressFamily != IpAddressFamily.InterNetworkV6)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
catch (HttpException)
|
||||
{
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.ErrorException("Error getting connection info", ex);
|
||||
}
|
||||
}
|
||||
|
||||
// If this produced an ipv6 address, try again
|
||||
if (validIpAddress != null && validIpAddress.AddressFamily == IpAddressFamily.InterNetworkV6)
|
||||
{
|
||||
foreach (var ipLookupUrl in _ipLookups)
|
||||
{
|
||||
try
|
||||
{
|
||||
var newAddress = await GetIpAddress(ipLookupUrl, true).ConfigureAwait(false);
|
||||
|
||||
// Try to find the ipv4 address, if present
|
||||
if (newAddress.AddressFamily != IpAddressFamily.InterNetworkV6)
|
||||
{
|
||||
validIpAddress = newAddress;
|
||||
break;
|
||||
}
|
||||
}
|
||||
catch (HttpException)
|
||||
{
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.ErrorException("Error getting connection info", ex);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (validIpAddress != null)
|
||||
{
|
||||
((ConnectManager)_connectManager).OnWanAddressResolved(validIpAddress);
|
||||
CacheAddress(validIpAddress);
|
||||
}
|
||||
}
|
||||
|
||||
private async Task<IpAddressInfo> GetIpAddress(string lookupUrl, bool preferIpv4 = false)
|
||||
{
|
||||
// Sometimes whatismyipaddress might fail, but it won't do us any good having users raise alarms over it.
|
||||
var logErrors = false;
|
||||
|
||||
#if DEBUG
|
||||
logErrors = true;
|
||||
#endif
|
||||
using (var stream = await _httpClient.Get(new HttpRequestOptions
|
||||
{
|
||||
Url = lookupUrl,
|
||||
UserAgent = "Emby/" + _appHost.ApplicationVersion,
|
||||
LogErrors = logErrors,
|
||||
|
||||
// Seeing block length errors with our server
|
||||
EnableHttpCompression = false,
|
||||
PreferIpv4 = preferIpv4,
|
||||
BufferContent = false
|
||||
|
||||
}).ConfigureAwait(false))
|
||||
{
|
||||
using (var reader = new StreamReader(stream))
|
||||
{
|
||||
var addressString = await reader.ReadToEndAsync().ConfigureAwait(false);
|
||||
|
||||
return _networkManager.ParseIpAddress(addressString);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private string CacheFilePath
|
||||
{
|
||||
get { return Path.Combine(_appPaths.DataPath, "wan.dat"); }
|
||||
}
|
||||
|
||||
private void CacheAddress(IpAddressInfo address)
|
||||
{
|
||||
if (_cachedIpAddress != null && _cachedIpAddress.Equals(address))
|
||||
{
|
||||
// no need to update the file if the address has not changed
|
||||
return;
|
||||
}
|
||||
|
||||
var path = CacheFilePath;
|
||||
|
||||
try
|
||||
{
|
||||
_fileSystem.CreateDirectory(Path.GetDirectoryName(path));
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
_fileSystem.WriteAllText(path, _encryption.EncryptString(address.ToString()), Encoding.UTF8);
|
||||
_cachedIpAddress = address;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.ErrorException("Error saving data", ex);
|
||||
}
|
||||
}
|
||||
|
||||
private void LoadCachedAddress()
|
||||
{
|
||||
var path = CacheFilePath;
|
||||
|
||||
_logger.Info("Loading data from {0}", path);
|
||||
|
||||
try
|
||||
{
|
||||
var endpoint = _encryption.DecryptString(_fileSystem.ReadAllText(path, Encoding.UTF8));
|
||||
IpAddressInfo ipAddress;
|
||||
|
||||
if (_networkManager.TryParseIpAddress(endpoint, out ipAddress))
|
||||
{
|
||||
_cachedIpAddress = ipAddress;
|
||||
((ConnectManager)_connectManager).OnWanAddressResolved(ipAddress);
|
||||
}
|
||||
}
|
||||
catch (IOException)
|
||||
{
|
||||
// File isn't there. no biggie
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.ErrorException("Error loading data", ex);
|
||||
}
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
if (_timer != null)
|
||||
{
|
||||
_timer.Dispose();
|
||||
_timer = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,85 +0,0 @@
|
||||
using MediaBrowser.Model.Configuration;
|
||||
using MediaBrowser.Model.Connect;
|
||||
|
||||
namespace Emby.Server.Implementations.Connect
|
||||
{
|
||||
public class ServerRegistrationResponse
|
||||
{
|
||||
public string Id { get; set; }
|
||||
public string Url { get; set; }
|
||||
public string Name { get; set; }
|
||||
public string AccessKey { get; set; }
|
||||
}
|
||||
|
||||
public class UpdateServerRegistrationResponse
|
||||
{
|
||||
public string Id { get; set; }
|
||||
public string Url { get; set; }
|
||||
public string Name { get; set; }
|
||||
}
|
||||
|
||||
public class GetConnectUserResponse
|
||||
{
|
||||
public string Id { get; set; }
|
||||
public string Name { get; set; }
|
||||
public string DisplayName { get; set; }
|
||||
public string Email { get; set; }
|
||||
public bool IsActive { get; set; }
|
||||
public string ImageUrl { get; set; }
|
||||
}
|
||||
|
||||
public class ServerUserAuthorizationResponse
|
||||
{
|
||||
public string Id { get; set; }
|
||||
public string ServerId { get; set; }
|
||||
public string UserId { get; set; }
|
||||
public string AccessToken { get; set; }
|
||||
public string DateCreated { get; set; }
|
||||
public bool IsActive { get; set; }
|
||||
public string AcceptStatus { get; set; }
|
||||
public string UserType { get; set; }
|
||||
public string UserImageUrl { get; set; }
|
||||
public string UserName { get; set; }
|
||||
}
|
||||
|
||||
public class ConnectUserPreferences
|
||||
{
|
||||
public string[] PreferredAudioLanguages { get; set; }
|
||||
public bool PlayDefaultAudioTrack { get; set; }
|
||||
public string[] PreferredSubtitleLanguages { get; set; }
|
||||
public SubtitlePlaybackMode SubtitleMode { get; set; }
|
||||
public bool GroupMoviesIntoBoxSets { get; set; }
|
||||
|
||||
public ConnectUserPreferences()
|
||||
{
|
||||
PreferredAudioLanguages = new string[] { };
|
||||
PreferredSubtitleLanguages = new string[] { };
|
||||
}
|
||||
|
||||
public static ConnectUserPreferences FromUserConfiguration(UserConfiguration config)
|
||||
{
|
||||
return new ConnectUserPreferences
|
||||
{
|
||||
PlayDefaultAudioTrack = config.PlayDefaultAudioTrack,
|
||||
SubtitleMode = config.SubtitleMode,
|
||||
PreferredAudioLanguages = string.IsNullOrWhiteSpace(config.AudioLanguagePreference) ? new string[] { } : new[] { config.AudioLanguagePreference },
|
||||
PreferredSubtitleLanguages = string.IsNullOrWhiteSpace(config.SubtitleLanguagePreference) ? new string[] { } : new[] { config.SubtitleLanguagePreference }
|
||||
};
|
||||
}
|
||||
|
||||
public void MergeInto(UserConfiguration config)
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
public class UserPreferencesDto<T>
|
||||
{
|
||||
public T data { get; set; }
|
||||
}
|
||||
|
||||
public class ConnectAuthorizationInternal : ConnectAuthorization
|
||||
{
|
||||
public string AccessToken { get; set; }
|
||||
}
|
||||
}
|
||||
@@ -1,29 +0,0 @@
|
||||
using System.Text.RegularExpressions;
|
||||
|
||||
namespace Emby.Server.Implementations.Connect
|
||||
{
|
||||
public static class Validator
|
||||
{
|
||||
static readonly Regex ValidEmailRegex = CreateValidEmailRegex();
|
||||
|
||||
/// <summary>
|
||||
/// Taken from http://haacked.com/archive/2007/08/21/i-knew-how-to-validate-an-email-address-until-i.aspx
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
private static Regex CreateValidEmailRegex()
|
||||
{
|
||||
const string validEmailPattern = @"^(?!\.)(""([^""\r\\]|\\[""\r\\])*""|"
|
||||
+ @"([-a-z0-9!#$%&'*+/=?^_`{|}~]|(?<!\.)\.)*)(?<!\.)"
|
||||
+ @"@[a-z0-9][\w\.-]*[a-z0-9]\.[a-z][a-z\.]*[a-z]$";
|
||||
|
||||
return new Regex(validEmailPattern, RegexOptions.IgnoreCase);
|
||||
}
|
||||
|
||||
internal static bool EmailIsValid(string emailAddress)
|
||||
{
|
||||
bool isValid = ValidEmailRegex.IsMatch(emailAddress);
|
||||
|
||||
return isValid;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1031,7 +1031,7 @@ namespace Emby.Server.Implementations.Dto
|
||||
|
||||
if (fields.Contains(ItemFields.Path))
|
||||
{
|
||||
dto.Path = GetMappedPath(item);
|
||||
dto.Path = GetMappedPath(item, owner);
|
||||
}
|
||||
|
||||
dto.PremiereDate = item.PremiereDate;
|
||||
@@ -1566,7 +1566,7 @@ namespace Emby.Server.Implementations.Dto
|
||||
}
|
||||
}
|
||||
|
||||
private string GetMappedPath(BaseItem item)
|
||||
private string GetMappedPath(BaseItem item, BaseItem ownerItem)
|
||||
{
|
||||
var path = item.Path;
|
||||
|
||||
@@ -1574,7 +1574,7 @@ namespace Emby.Server.Implementations.Dto
|
||||
|
||||
if (locationType == LocationType.FileSystem || locationType == LocationType.Offline)
|
||||
{
|
||||
path = _libraryManager.GetPathAfterNetworkSubstitution(path, item);
|
||||
path = _libraryManager.GetPathAfterNetworkSubstitution(path, ownerItem ?? item);
|
||||
}
|
||||
|
||||
return path;
|
||||
|
||||
@@ -35,6 +35,9 @@
|
||||
<Compile Include="Activity\ActivityLogEntryPoint.cs" />
|
||||
<Compile Include="Activity\ActivityManager.cs" />
|
||||
<Compile Include="Activity\ActivityRepository.cs" />
|
||||
<Compile Include="AppBase\BaseApplicationPaths.cs" />
|
||||
<Compile Include="AppBase\BaseConfigurationManager.cs" />
|
||||
<Compile Include="AppBase\ConfigurationHelper.cs" />
|
||||
<Compile Include="Branding\BrandingConfigurationFactory.cs" />
|
||||
<Compile Include="Browser\BrowserLauncher.cs" />
|
||||
<Compile Include="Channels\ChannelConfigurations.cs" />
|
||||
@@ -46,11 +49,7 @@
|
||||
<Compile Include="Collections\CollectionImageProvider.cs" />
|
||||
<Compile Include="Collections\CollectionManager.cs" />
|
||||
<Compile Include="Collections\CollectionsDynamicFolder.cs" />
|
||||
<Compile Include="Connect\ConnectData.cs" />
|
||||
<Compile Include="Connect\ConnectEntryPoint.cs" />
|
||||
<Compile Include="Connect\ConnectManager.cs" />
|
||||
<Compile Include="Connect\Responses.cs" />
|
||||
<Compile Include="Connect\Validator.cs" />
|
||||
<Compile Include="Configuration\ServerConfigurationManager.cs" />
|
||||
<Compile Include="Data\ManagedConnection.cs" />
|
||||
<Compile Include="Data\SqliteDisplayPreferencesRepository.cs" />
|
||||
<Compile Include="Data\SqliteFileOrganizationRepository.cs" />
|
||||
@@ -179,6 +178,7 @@
|
||||
<Compile Include="LiveTv\TunerHosts\MulticastStream.cs" />
|
||||
<Compile Include="LiveTv\TunerHosts\QueueStream.cs" />
|
||||
<Compile Include="Localization\LocalizationManager.cs" />
|
||||
<Compile Include="Logging\UnhandledExceptionWriter.cs" />
|
||||
<Compile Include="MediaEncoder\EncodingManager.cs" />
|
||||
<Compile Include="Migrations\IVersionMigration.cs" />
|
||||
<Compile Include="Migrations\LibraryScanMigration.cs" />
|
||||
@@ -213,6 +213,7 @@
|
||||
<Compile Include="Security\MBLicenseFile.cs" />
|
||||
<Compile Include="Security\PluginSecurityManager.cs" />
|
||||
<Compile Include="Security\RegRecord.cs" />
|
||||
<Compile Include="ServerApplicationPaths.cs" />
|
||||
<Compile Include="ServerManager\ServerManager.cs" />
|
||||
<Compile Include="ServerManager\WebSocketConnection.cs" />
|
||||
<Compile Include="Services\ServicePath.cs" />
|
||||
|
||||
@@ -0,0 +1,43 @@
|
||||
using MediaBrowser.Common.Configuration;
|
||||
using MediaBrowser.Model.Logging;
|
||||
using System;
|
||||
using System.IO;
|
||||
using MediaBrowser.Model.IO;
|
||||
|
||||
namespace Emby.Server.Implementations.Logging
|
||||
{
|
||||
public class UnhandledExceptionWriter
|
||||
{
|
||||
private readonly IApplicationPaths _appPaths;
|
||||
private readonly ILogger _logger;
|
||||
private readonly ILogManager _logManager;
|
||||
private readonly IFileSystem _fileSystem;
|
||||
private readonly IConsoleLogger _console;
|
||||
|
||||
public UnhandledExceptionWriter(IApplicationPaths appPaths, ILogger logger, ILogManager logManager, IFileSystem fileSystem, IConsoleLogger console)
|
||||
{
|
||||
_appPaths = appPaths;
|
||||
_logger = logger;
|
||||
_logManager = logManager;
|
||||
_fileSystem = fileSystem;
|
||||
_console = console;
|
||||
}
|
||||
|
||||
public void Log(Exception ex)
|
||||
{
|
||||
_logger.ErrorException("UnhandledException", ex);
|
||||
_logManager.Flush();
|
||||
|
||||
var path = Path.Combine(_appPaths.LogDirectoryPath, "unhandled_" + Guid.NewGuid() + ".txt");
|
||||
_fileSystem.CreateDirectory(Path.GetDirectoryName(path));
|
||||
|
||||
var builder = LogHelper.GetLogMessage(ex);
|
||||
|
||||
// Write to console just in case file logging fails
|
||||
_console.WriteLine("UnhandledException");
|
||||
_console.WriteLine(builder.ToString());
|
||||
|
||||
_fileSystem.WriteAllText(path, builder.ToString());
|
||||
}
|
||||
}
|
||||
}
|
||||
234
Emby.Server.Implementations/ServerApplicationPaths.cs
Normal file
234
Emby.Server.Implementations/ServerApplicationPaths.cs
Normal file
@@ -0,0 +1,234 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
using Emby.Server.Implementations.AppBase;
|
||||
using MediaBrowser.Controller;
|
||||
|
||||
namespace Emby.Server.Implementations
|
||||
{
|
||||
/// <summary>
|
||||
/// Extends BaseApplicationPaths to add paths that are only applicable on the server
|
||||
/// </summary>
|
||||
public class ServerApplicationPaths : BaseApplicationPaths, IServerApplicationPaths
|
||||
{
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="BaseApplicationPaths" /> class.
|
||||
/// </summary>
|
||||
public ServerApplicationPaths(string programDataPath, string appFolderPath, string applicationResourcesPath, Action<string> createDirectoryFn)
|
||||
: base(programDataPath, appFolderPath, createDirectoryFn)
|
||||
{
|
||||
ApplicationResourcesPath = applicationResourcesPath;
|
||||
}
|
||||
|
||||
public string ApplicationResourcesPath { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the path to the base root media directory
|
||||
/// </summary>
|
||||
/// <value>The root folder path.</value>
|
||||
public string RootFolderPath
|
||||
{
|
||||
get
|
||||
{
|
||||
return Path.Combine(ProgramDataPath, "root");
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the path to the default user view directory. Used if no specific user view is defined.
|
||||
/// </summary>
|
||||
/// <value>The default user views path.</value>
|
||||
public string DefaultUserViewsPath
|
||||
{
|
||||
get
|
||||
{
|
||||
return Path.Combine(RootFolderPath, "default");
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the path to localization data.
|
||||
/// </summary>
|
||||
/// <value>The localization path.</value>
|
||||
public string LocalizationPath
|
||||
{
|
||||
get
|
||||
{
|
||||
return Path.Combine(ProgramDataPath, "localization");
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The _ibn path
|
||||
/// </summary>
|
||||
private string _ibnPath;
|
||||
/// <summary>
|
||||
/// Gets the path to the Images By Name directory
|
||||
/// </summary>
|
||||
/// <value>The images by name path.</value>
|
||||
public string ItemsByNamePath
|
||||
{
|
||||
get
|
||||
{
|
||||
return _ibnPath ?? (_ibnPath = Path.Combine(ProgramDataPath, "ImagesByName"));
|
||||
}
|
||||
set
|
||||
{
|
||||
_ibnPath = value;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the path to the People directory
|
||||
/// </summary>
|
||||
/// <value>The people path.</value>
|
||||
public string PeoplePath
|
||||
{
|
||||
get
|
||||
{
|
||||
return Path.Combine(ItemsByNamePath, "People");
|
||||
}
|
||||
}
|
||||
|
||||
public string ArtistsPath
|
||||
{
|
||||
get
|
||||
{
|
||||
return Path.Combine(ItemsByNamePath, "artists");
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the path to the Genre directory
|
||||
/// </summary>
|
||||
/// <value>The genre path.</value>
|
||||
public string GenrePath
|
||||
{
|
||||
get
|
||||
{
|
||||
return Path.Combine(ItemsByNamePath, "Genre");
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the path to the Genre directory
|
||||
/// </summary>
|
||||
/// <value>The genre path.</value>
|
||||
public string MusicGenrePath
|
||||
{
|
||||
get
|
||||
{
|
||||
return Path.Combine(ItemsByNamePath, "MusicGenre");
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the path to the Studio directory
|
||||
/// </summary>
|
||||
/// <value>The studio path.</value>
|
||||
public string StudioPath
|
||||
{
|
||||
get
|
||||
{
|
||||
return Path.Combine(ItemsByNamePath, "Studio");
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the path to the Year directory
|
||||
/// </summary>
|
||||
/// <value>The year path.</value>
|
||||
public string YearPath
|
||||
{
|
||||
get
|
||||
{
|
||||
return Path.Combine(ItemsByNamePath, "Year");
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the path to the General IBN directory
|
||||
/// </summary>
|
||||
/// <value>The general path.</value>
|
||||
public string GeneralPath
|
||||
{
|
||||
get
|
||||
{
|
||||
return Path.Combine(ItemsByNamePath, "general");
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the path to the Ratings IBN directory
|
||||
/// </summary>
|
||||
/// <value>The ratings path.</value>
|
||||
public string RatingsPath
|
||||
{
|
||||
get
|
||||
{
|
||||
return Path.Combine(ItemsByNamePath, "ratings");
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the media info images path.
|
||||
/// </summary>
|
||||
/// <value>The media info images path.</value>
|
||||
public string MediaInfoImagesPath
|
||||
{
|
||||
get
|
||||
{
|
||||
return Path.Combine(ItemsByNamePath, "mediainfo");
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the path to the user configuration directory
|
||||
/// </summary>
|
||||
/// <value>The user configuration directory path.</value>
|
||||
public string UserConfigurationDirectoryPath
|
||||
{
|
||||
get
|
||||
{
|
||||
return Path.Combine(ConfigurationDirectoryPath, "users");
|
||||
}
|
||||
}
|
||||
|
||||
private string _transcodingTempPath;
|
||||
public string TranscodingTempPath
|
||||
{
|
||||
get
|
||||
{
|
||||
return _transcodingTempPath ?? (_transcodingTempPath = Path.Combine(ProgramDataPath, "transcoding-temp"));
|
||||
}
|
||||
set
|
||||
{
|
||||
_transcodingTempPath = value;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the game genre path.
|
||||
/// </summary>
|
||||
/// <value>The game genre path.</value>
|
||||
public string GameGenrePath
|
||||
{
|
||||
get
|
||||
{
|
||||
return Path.Combine(ItemsByNamePath, "GameGenre");
|
||||
}
|
||||
}
|
||||
|
||||
private string _internalMetadataPath;
|
||||
public string InternalMetadataPath
|
||||
{
|
||||
get
|
||||
{
|
||||
return _internalMetadataPath ?? (_internalMetadataPath = Path.Combine(DataPath, "metadata"));
|
||||
}
|
||||
set
|
||||
{
|
||||
_internalMetadataPath = value;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user