diff --git a/Emby.Common.Implementations/BaseApplicationHost.cs b/Emby.Common.Implementations/BaseApplicationHost.cs
index 147a43fa1..13bb85087 100644
--- a/Emby.Common.Implementations/BaseApplicationHost.cs
+++ b/Emby.Common.Implementations/BaseApplicationHost.cs
@@ -147,7 +147,7 @@ namespace Emby.Common.Implementations
/// The configuration manager.
protected IConfigurationManager ConfigurationManager { get; private set; }
- protected IFileSystem FileSystemManager { get; private set; }
+ public IFileSystem FileSystemManager { get; private set; }
protected IIsoManager IsoManager { get; private set; }
@@ -873,7 +873,13 @@ return null;
/// Gets or sets a value indicating whether this instance can self update.
///
/// true if this instance can self update; otherwise, false.
- public abstract bool CanSelfUpdate { get; }
+ public virtual bool CanSelfUpdate
+ {
+ get
+ {
+ return false;
+ }
+ }
///
/// Checks for update.
diff --git a/Emby.Common.Implementations/ScheduledTasks/ScheduledTaskWorker.cs b/Emby.Common.Implementations/ScheduledTasks/ScheduledTaskWorker.cs
index de528a94f..f0518f69e 100644
--- a/Emby.Common.Implementations/ScheduledTasks/ScheduledTaskWorker.cs
+++ b/Emby.Common.Implementations/ScheduledTasks/ScheduledTaskWorker.cs
@@ -379,7 +379,7 @@ namespace Emby.Common.Implementations.ScheduledTasks
/// Cannot execute a Task that is already running
public async Task Execute(TaskExecutionOptions options)
{
- var task = ExecuteInternal(options);
+ var task = Task.Run(async () => await ExecuteInternal(options).ConfigureAwait(false));
_currentTask = task;
diff --git a/Emby.Server.Core/ApplicationHost.cs b/Emby.Server.Core/ApplicationHost.cs
index a3c228a58..4425d1a0b 100644
--- a/Emby.Server.Core/ApplicationHost.cs
+++ b/Emby.Server.Core/ApplicationHost.cs
@@ -83,7 +83,6 @@ using Emby.Dlna.MediaReceiverRegistrar;
using Emby.Dlna.Ssdp;
using Emby.Server.Core;
using Emby.Server.Implementations.Activity;
-using Emby.Server.Core.Configuration;
using Emby.Server.Implementations.Devices;
using Emby.Server.Implementations.FFMpeg;
using Emby.Server.Core.IO;
@@ -91,10 +90,8 @@ using Emby.Server.Core.Localization;
using Emby.Server.Implementations.Migrations;
using Emby.Server.Implementations.Security;
using Emby.Server.Implementations.Social;
-using Emby.Server.Implementations.Sync;
using Emby.Server.Implementations.Channels;
using Emby.Server.Implementations.Collections;
-using Emby.Server.Implementations.Connect;
using Emby.Server.Implementations.Dto;
using Emby.Server.Implementations.EntryPoints;
using Emby.Server.Implementations.FileOrganization;
@@ -111,7 +108,6 @@ using Emby.Server.Implementations;
using Emby.Server.Implementations.ServerManager;
using Emby.Server.Implementations.Session;
using Emby.Server.Implementations.Social;
-using Emby.Server.Implementations.Sync;
using Emby.Server.Implementations.TV;
using Emby.Server.Implementations.Updates;
using MediaBrowser.Model.Activity;
@@ -134,6 +130,7 @@ using Emby.Drawing;
using Emby.Server.Implementations.Migrations;
using MediaBrowser.Model.Diagnostics;
using Emby.Common.Implementations.Diagnostics;
+using Emby.Server.Implementations.Configuration;
namespace Emby.Server.Core
{
@@ -312,7 +309,13 @@ namespace Emby.Server.Core
}
}
- public abstract bool SupportsRunningAsService { get; }
+ public virtual bool SupportsRunningAsService
+ {
+ get
+ {
+ return false;
+ }
+ }
///
/// Gets the name.
@@ -326,14 +329,26 @@ namespace Emby.Server.Core
}
}
- public abstract bool IsRunningAsService { get; }
+ public virtual bool IsRunningAsService
+ {
+ get
+ {
+ return false;
+ }
+ }
private Assembly GetAssembly(Type type)
{
return type.GetTypeInfo().Assembly;
}
- public abstract bool SupportsAutoRunAtStartup { get; }
+ public virtual bool SupportsAutoRunAtStartup
+ {
+ get
+ {
+ return EnvironmentInfo.OperatingSystem == MediaBrowser.Model.System.OperatingSystem.Windows;
+ }
+ }
private void SetBaseExceptionMessage()
{
@@ -508,6 +523,9 @@ namespace Emby.Server.Core
}
}
+ protected abstract IConnectManager CreateConnectManager();
+ protected abstract ISyncManager CreateSyncManager();
+
///
/// Registers resources that classes will depend on
///
@@ -568,9 +586,6 @@ namespace Emby.Server.Core
AuthenticationRepository = await GetAuthenticationRepository().ConfigureAwait(false);
RegisterSingleInstance(AuthenticationRepository);
- SyncRepository = GetSyncRepository();
- RegisterSingleInstance(SyncRepository);
-
UserManager = new UserManager(LogManager.GetLogger("UserManager"), ServerConfigurationManager, UserRepository, XmlSerializer, NetworkManager, () => ImageProcessor, () => DtoService, () => ConnectManager, this, JsonSerializer, FileSystemManager, CryptographyProvider, _defaultUserNameFactory());
RegisterSingleInstance(UserManager);
@@ -608,7 +623,7 @@ namespace Emby.Server.Core
TVSeriesManager = new TVSeriesManager(UserManager, UserDataManager, LibraryManager, ServerConfigurationManager);
RegisterSingleInstance(TVSeriesManager);
- SyncManager = new SyncManager(LibraryManager, SyncRepository, ImageProcessor, LogManager.GetLogger("SyncManager"), UserManager, () => DtoService, this, TVSeriesManager, () => MediaEncoder, FileSystemManager, () => SubtitleEncoder, ServerConfigurationManager, UserDataManager, () => MediaSourceManager, JsonSerializer, TaskManager, MemoryStreamFactory);
+ SyncManager = CreateSyncManager();
RegisterSingleInstance(SyncManager);
DtoService = new DtoService(LogManager.GetLogger("DtoService"), LibraryManager, UserDataManager, ItemRepository, ImageProcessor, ServerConfigurationManager, FileSystemManager, ProviderManager, () => ChannelManager, SyncManager, this, () => DeviceManager, () => MediaSourceManager, () => LiveTvManager);
@@ -617,7 +632,7 @@ namespace Emby.Server.Core
var encryptionManager = new EncryptionManager();
RegisterSingleInstance(encryptionManager);
- ConnectManager = new ConnectManager(LogManager.GetLogger("ConnectManager"), ApplicationPaths, JsonSerializer, encryptionManager, HttpClient, this, ServerConfigurationManager, UserManager, ProviderManager, SecurityManager, FileSystemManager);
+ ConnectManager = CreateConnectManager();
RegisterSingleInstance(ConnectManager);
DeviceManager = new DeviceManager(new DeviceRepository(ApplicationPaths, JsonSerializer, LogManager.GetLogger("DeviceManager"), FileSystemManager), UserManager, FileSystemManager, LibraryMonitor, ServerConfigurationManager, LogManager.GetLogger("DeviceManager"), NetworkManager);
@@ -716,7 +731,13 @@ namespace Emby.Server.Core
await ((UserManager)UserManager).Initialize().ConfigureAwait(false);
}
- protected abstract bool SupportsDualModeSockets { get; }
+ protected virtual bool SupportsDualModeSockets
+ {
+ get
+ {
+ return true;
+ }
+ }
private ICertificate GetCertificate(string certificateLocation)
{
@@ -761,7 +782,77 @@ namespace Emby.Server.Core
return new ImageProcessor(LogManager.GetLogger("ImageProcessor"), ServerConfigurationManager.ApplicationPaths, FileSystemManager, JsonSerializer, ImageEncoder, maxConcurrentImageProcesses, () => LibraryManager, TimerFactory);
}
- protected abstract FFMpegInstallInfo GetFfmpegInstallInfo();
+ protected virtual FFMpegInstallInfo GetFfmpegInstallInfo()
+ {
+ var info = new FFMpegInstallInfo();
+
+ // Windows builds: http://ffmpeg.zeranoe.com/builds/
+ // Linux builds: http://johnvansickle.com/ffmpeg/
+ // OS X builds: http://ffmpegmac.net/
+ // OS X x64: http://www.evermeet.cx/ffmpeg/
+
+ if (EnvironmentInfo.OperatingSystem == MediaBrowser.Model.System.OperatingSystem.Linux)
+ {
+ info.FFMpegFilename = "ffmpeg";
+ info.FFProbeFilename = "ffprobe";
+ info.ArchiveType = "7z";
+ info.Version = "20160215";
+ info.DownloadUrls = GetLinuxDownloadUrls();
+ }
+ else if (EnvironmentInfo.OperatingSystem == MediaBrowser.Model.System.OperatingSystem.Windows)
+ {
+ info.FFMpegFilename = "ffmpeg.exe";
+ info.FFProbeFilename = "ffprobe.exe";
+ info.Version = "20160410";
+ info.ArchiveType = "7z";
+ info.DownloadUrls = GetWindowsDownloadUrls();
+ }
+ else
+ {
+ // No version available - user requirement
+ info.DownloadUrls = new string[] { };
+ }
+
+ return info;
+ }
+
+ private string[] GetWindowsDownloadUrls()
+ {
+ switch (EnvironmentInfo.SystemArchitecture)
+ {
+ case Architecture.X64:
+ return new[]
+ {
+ "https://github.com/MediaBrowser/Emby.Resources/raw/master/ffmpeg/windows/ffmpeg-20160410-win64.7z"
+ };
+ case Architecture.X86:
+ return new[]
+ {
+ "https://github.com/MediaBrowser/Emby.Resources/raw/master/ffmpeg/windows/ffmpeg-20160410-win32.7z"
+ };
+ }
+
+ return new string[] { };
+ }
+
+ private string[] GetLinuxDownloadUrls()
+ {
+ switch (EnvironmentInfo.SystemArchitecture)
+ {
+ case Architecture.X64:
+ return new[]
+ {
+ "https://github.com/MediaBrowser/Emby.Resources/raw/master/ffmpeg/linux/ffmpeg-git-20160215-64bit-static.7z"
+ };
+ case Architecture.X86:
+ return new[]
+ {
+ "https://github.com/MediaBrowser/Emby.Resources/raw/master/ffmpeg/linux/ffmpeg-git-20160215-32bit-static.7z"
+ };
+ }
+
+ return new string[] { };
+ }
///
/// Registers the media encoder.
@@ -849,21 +940,12 @@ namespace Emby.Server.Core
return repo;
}
- private ISyncRepository GetSyncRepository()
- {
- var repo = new SyncRepository(LogManager.GetLogger("SyncRepository"), JsonSerializer, ServerConfigurationManager.ApplicationPaths);
-
- repo.Initialize();
-
- return repo;
- }
-
///
/// Configures the repositories.
///
private void ConfigureNotificationsRepository()
{
- var repo = new SqliteNotificationsRepository(LogManager.GetLogger("SqliteNotificationsRepository"), ServerConfigurationManager.ApplicationPaths);
+ var repo = new SqliteNotificationsRepository(LogManager.GetLogger("SqliteNotificationsRepository"), ServerConfigurationManager.ApplicationPaths, FileSystemManager);
repo.Initialize();
@@ -1158,7 +1240,7 @@ namespace Emby.Server.Core
list.Add(GetAssembly(typeof(InstallationManager)));
// Emby.Server.Core
- list.Add(GetAssembly(typeof(ServerApplicationPaths)));
+ list.Add(GetAssembly(typeof(ApplicationHost)));
// MediaEncoding
list.Add(GetAssembly(typeof(MediaEncoder)));
@@ -1489,7 +1571,10 @@ namespace Emby.Server.Core
}
}
- protected abstract void AuthorizeServer();
+ protected virtual void AuthorizeServer()
+ {
+ throw new NotImplementedException();
+ }
public event EventHandler HasUpdateAvailableChanged;
@@ -1565,7 +1650,10 @@ namespace Emby.Server.Core
}
}
- protected abstract void ConfigureAutoRunInternal(bool autorun);
+ protected virtual void ConfigureAutoRunInternal(bool autorun)
+ {
+ throw new NotImplementedException();
+ }
///
/// This returns localhost in the case of no external dns, and the hostname if the
@@ -1631,7 +1719,10 @@ namespace Emby.Server.Core
EnableLoopbackInternal(appName);
}
- protected abstract void EnableLoopbackInternal(string appName);
+ protected virtual void EnableLoopbackInternal(string appName)
+ {
+
+ }
private void RegisterModules()
{
diff --git a/Emby.Server.Core/Emby.Server.Core.xproj b/Emby.Server.Core/Emby.Server.Core.xproj
index 00f7664bd..fefaa6284 100644
--- a/Emby.Server.Core/Emby.Server.Core.xproj
+++ b/Emby.Server.Core/Emby.Server.Core.xproj
@@ -16,7 +16,6 @@
2.0
-
diff --git a/Emby.Server.Core/EntryPoints/ExternalPortForwarding.cs b/Emby.Server.Core/EntryPoints/ExternalPortForwarding.cs
index eb3a71465..2c7e6a487 100644
--- a/Emby.Server.Core/EntryPoints/ExternalPortForwarding.cs
+++ b/Emby.Server.Core/EntryPoints/ExternalPortForwarding.cs
@@ -187,7 +187,10 @@ namespace Emby.Server.Core.EntryPoints
private void ClearCreatedRules(object state)
{
- _createdRules = new List();
+ lock (_createdRules)
+ {
+ _createdRules.Clear();
+ }
lock (_usnsHandled)
{
_usnsHandled.Clear();
@@ -236,16 +239,23 @@ namespace Emby.Server.Core.EntryPoints
var address = device.LocalAddress.ToString();
- if (!_createdRules.Contains(address))
+ lock (_createdRules)
{
- _createdRules.Add(address);
-
- var success = await CreatePortMap(device, _appHost.HttpPort, _config.Configuration.PublicPort).ConfigureAwait(false);
-
- if (success)
+ if (!_createdRules.Contains(address))
{
- await CreatePortMap(device, _appHost.HttpsPort, _config.Configuration.PublicHttpsPort).ConfigureAwait(false);
+ _createdRules.Add(address);
}
+ else
+ {
+ return;
+ }
+ }
+
+ var success = await CreatePortMap(device, _appHost.HttpPort, _config.Configuration.PublicPort).ConfigureAwait(false);
+
+ if (success)
+ {
+ await CreatePortMap(device, _appHost.HttpsPort, _config.Configuration.PublicHttpsPort).ConfigureAwait(false);
}
}
diff --git a/Emby.Server.Core/Logging/ConsoleLogger.cs b/Emby.Server.Core/Logging/ConsoleLogger.cs
new file mode 100644
index 000000000..01eca7b7e
--- /dev/null
+++ b/Emby.Server.Core/Logging/ConsoleLogger.cs
@@ -0,0 +1,16 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Threading.Tasks;
+using MediaBrowser.Model.Logging;
+
+namespace Emby.Server.Core.Logging
+{
+ public class ConsoleLogger : IConsoleLogger
+ {
+ public void WriteLine(string message)
+ {
+ Console.WriteLine(message);
+ }
+ }
+}
diff --git a/Emby.Server.Core/project.json b/Emby.Server.Core/project.json
index e987da6aa..70543d7df 100644
--- a/Emby.Server.Core/project.json
+++ b/Emby.Server.Core/project.json
@@ -56,9 +56,6 @@
"Emby.Drawing": {
"target": "project"
},
- "ServiceStack": {
- "target": "project"
- },
"SocketHttpListener.Portable": {
"target": "project"
}
@@ -121,9 +118,6 @@
},
"SocketHttpListener.Portable": {
"target": "project"
- },
- "ServiceStack": {
- "target": "project"
}
}
}
diff --git a/Emby.Common.Implementations/BaseApplicationPaths.cs b/Emby.Server.Implementations/AppBase/BaseApplicationPaths.cs
similarity index 93%
rename from Emby.Common.Implementations/BaseApplicationPaths.cs
rename to Emby.Server.Implementations/AppBase/BaseApplicationPaths.cs
index 8792778ba..54d1d5302 100644
--- a/Emby.Common.Implementations/BaseApplicationPaths.cs
+++ b/Emby.Server.Implementations/AppBase/BaseApplicationPaths.cs
@@ -1,7 +1,8 @@
-using System.IO;
+using System;
+using System.IO;
using MediaBrowser.Common.Configuration;
-namespace Emby.Common.Implementations
+namespace Emby.Server.Implementations.AppBase
{
///
/// Provides a base class to hold common application paths used by both the Ui and Server.
@@ -12,12 +13,15 @@ namespace Emby.Common.Implementations
///
/// Initializes a new instance of the class.
///
- protected BaseApplicationPaths(string programDataPath, string appFolderPath)
+ protected BaseApplicationPaths(string programDataPath, string appFolderPath, Action createDirectoryFn)
{
ProgramDataPath = programDataPath;
ProgramSystemPath = appFolderPath;
+ CreateDirectoryFn = createDirectoryFn;
}
+ protected Action CreateDirectoryFn;
+
public string ProgramDataPath { get; private set; }
///
@@ -41,7 +45,7 @@ namespace Emby.Common.Implementations
{
_dataDirectory = Path.Combine(ProgramDataPath, "data");
- Directory.CreateDirectory(_dataDirectory);
+ CreateDirectoryFn(_dataDirectory);
}
return _dataDirectory;
@@ -148,7 +152,7 @@ namespace Emby.Common.Implementations
{
_cachePath = Path.Combine(ProgramDataPath, "cache");
- Directory.CreateDirectory(_cachePath);
+ CreateDirectoryFn(_cachePath);
}
return _cachePath;
diff --git a/Emby.Common.Implementations/Configuration/BaseConfigurationManager.cs b/Emby.Server.Implementations/AppBase/BaseConfigurationManager.cs
similarity index 99%
rename from Emby.Common.Implementations/Configuration/BaseConfigurationManager.cs
rename to Emby.Server.Implementations/AppBase/BaseConfigurationManager.cs
index 27c9fe615..13874223c 100644
--- a/Emby.Common.Implementations/Configuration/BaseConfigurationManager.cs
+++ b/Emby.Server.Implementations/AppBase/BaseConfigurationManager.cs
@@ -7,13 +7,12 @@ using System.Threading;
using MediaBrowser.Common.Configuration;
using MediaBrowser.Common.Events;
using MediaBrowser.Common.Extensions;
-using Emby.Common.Implementations;
using MediaBrowser.Model.Configuration;
using MediaBrowser.Model.IO;
using MediaBrowser.Model.Logging;
using MediaBrowser.Model.Serialization;
-namespace Emby.Common.Implementations.Configuration
+namespace Emby.Server.Implementations.AppBase
{
///
/// Class BaseConfigurationManager
diff --git a/Emby.Common.Implementations/Configuration/ConfigurationHelper.cs b/Emby.Server.Implementations/AppBase/ConfigurationHelper.cs
similarity index 97%
rename from Emby.Common.Implementations/Configuration/ConfigurationHelper.cs
rename to Emby.Server.Implementations/AppBase/ConfigurationHelper.cs
index 0d43a651e..ad2f45945 100644
--- a/Emby.Common.Implementations/Configuration/ConfigurationHelper.cs
+++ b/Emby.Server.Implementations/AppBase/ConfigurationHelper.cs
@@ -4,7 +4,7 @@ using System.Linq;
using MediaBrowser.Model.IO;
using MediaBrowser.Model.Serialization;
-namespace Emby.Common.Implementations.Configuration
+namespace Emby.Server.Implementations.AppBase
{
///
/// Class ConfigurationHelper
diff --git a/Emby.Server.Core/Configuration/ServerConfigurationManager.cs b/Emby.Server.Implementations/Configuration/ServerConfigurationManager.cs
similarity index 97%
rename from Emby.Server.Core/Configuration/ServerConfigurationManager.cs
rename to Emby.Server.Implementations/Configuration/ServerConfigurationManager.cs
index eb3d8b9f9..2241e9377 100644
--- a/Emby.Server.Core/Configuration/ServerConfigurationManager.cs
+++ b/Emby.Server.Implementations/Configuration/ServerConfigurationManager.cs
@@ -2,7 +2,7 @@
using System.Collections.Generic;
using System.IO;
using System.Linq;
-using Emby.Common.Implementations.Configuration;
+using Emby.Server.Implementations.AppBase;
using MediaBrowser.Common.Configuration;
using MediaBrowser.Common.Events;
using MediaBrowser.Controller;
@@ -17,7 +17,7 @@ using MediaBrowser.Model.IO;
using MediaBrowser.Model.Logging;
using MediaBrowser.Model.Serialization;
-namespace Emby.Server.Core.Configuration
+namespace Emby.Server.Implementations.Configuration
{
///
/// Class ServerConfigurationManager
@@ -187,7 +187,7 @@ namespace Emby.Server.Core.Configuration
// Validate
if (!FileSystem.DirectoryExists(newPath))
{
- throw new DirectoryNotFoundException(string.Format("{0} does not exist.", newPath));
+ throw new FileNotFoundException(string.Format("{0} does not exist.", newPath));
}
EnsureWriteAccess(newPath);
diff --git a/Emby.Server.Implementations/Connect/ConnectData.cs b/Emby.Server.Implementations/Connect/ConnectData.cs
deleted file mode 100644
index 41b89ce52..000000000
--- a/Emby.Server.Implementations/Connect/ConnectData.cs
+++ /dev/null
@@ -1,36 +0,0 @@
-using System;
-using System.Collections.Generic;
-
-namespace Emby.Server.Implementations.Connect
-{
- public class ConnectData
- {
- ///
- /// Gets or sets the server identifier.
- ///
- /// The server identifier.
- public string ServerId { get; set; }
- ///
- /// Gets or sets the access key.
- ///
- /// The access key.
- public string AccessKey { get; set; }
-
- ///
- /// Gets or sets the authorizations.
- ///
- /// The authorizations.
- public List PendingAuthorizations { get; set; }
-
- ///
- /// Gets or sets the last authorizations refresh.
- ///
- /// The last authorizations refresh.
- public DateTime LastAuthorizationsRefresh { get; set; }
-
- public ConnectData()
- {
- PendingAuthorizations = new List();
- }
- }
-}
diff --git a/Emby.Server.Implementations/Connect/ConnectEntryPoint.cs b/Emby.Server.Implementations/Connect/ConnectEntryPoint.cs
deleted file mode 100644
index b5639773b..000000000
--- a/Emby.Server.Implementations/Connect/ConnectEntryPoint.cs
+++ /dev/null
@@ -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 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;
- }
- }
- }
-}
diff --git a/Emby.Server.Implementations/Connect/ConnectManager.cs b/Emby.Server.Implementations/Connect/ConnectManager.cs
deleted file mode 100644
index 8aac2a8c4..000000000
--- a/Emby.Server.Implementations/Connect/ConnectManager.cs
+++ /dev/null
@@ -1,1193 +0,0 @@
-using MediaBrowser.Common.Configuration;
-using MediaBrowser.Common.Net;
-using MediaBrowser.Common.Security;
-using MediaBrowser.Controller;
-using MediaBrowser.Controller.Configuration;
-using MediaBrowser.Controller.Connect;
-using MediaBrowser.Controller.Entities;
-using MediaBrowser.Controller.Library;
-using MediaBrowser.Controller.Providers;
-using MediaBrowser.Controller.Security;
-using MediaBrowser.Model.Connect;
-using MediaBrowser.Model.Entities;
-using MediaBrowser.Model.Logging;
-using MediaBrowser.Model.Net;
-using MediaBrowser.Model.Serialization;
-using System;
-using System.Collections.Generic;
-using System.Globalization;
-using System.IO;
-using System.Linq;
-using System.Net;
-using System.Text;
-using System.Threading;
-using System.Threading.Tasks;
-using MediaBrowser.Model.IO;
-using MediaBrowser.Common.Extensions;
-
-namespace Emby.Server.Implementations.Connect
-{
- public class ConnectManager : IConnectManager
- {
- private readonly SemaphoreSlim _operationLock = new SemaphoreSlim(1, 1);
-
- private readonly ILogger _logger;
- private readonly IApplicationPaths _appPaths;
- private readonly IJsonSerializer _json;
- private readonly IEncryptionManager _encryption;
- private readonly IHttpClient _httpClient;
- private readonly IServerApplicationHost _appHost;
- private readonly IServerConfigurationManager _config;
- private readonly IUserManager _userManager;
- private readonly IProviderManager _providerManager;
- private readonly ISecurityManager _securityManager;
- private readonly IFileSystem _fileSystem;
-
- private ConnectData _data = new ConnectData();
-
- public string ConnectServerId
- {
- get { return _data.ServerId; }
- }
- public string ConnectAccessKey
- {
- get { return _data.AccessKey; }
- }
-
- private IpAddressInfo DiscoveredWanIpAddress { get; set; }
-
- public string WanIpAddress
- {
- get
- {
- var address = _config.Configuration.WanDdns;
-
- if (!string.IsNullOrWhiteSpace(address))
- {
- Uri newUri;
-
- if (Uri.TryCreate(address, UriKind.Absolute, out newUri))
- {
- address = newUri.Host;
- }
- }
-
- if (string.IsNullOrWhiteSpace(address) && DiscoveredWanIpAddress != null)
- {
- if (DiscoveredWanIpAddress.AddressFamily == IpAddressFamily.InterNetworkV6)
- {
- address = "[" + DiscoveredWanIpAddress + "]";
- }
- else
- {
- address = DiscoveredWanIpAddress.ToString();
- }
- }
-
- return address;
- }
- }
-
- public string WanApiAddress
- {
- get
- {
- var ip = WanIpAddress;
-
- if (!string.IsNullOrEmpty(ip))
- {
- if (!ip.StartsWith("http://", StringComparison.OrdinalIgnoreCase) &&
- !ip.StartsWith("https://", StringComparison.OrdinalIgnoreCase))
- {
- ip = (_appHost.EnableHttps ? "https://" : "http://") + ip;
- }
-
- ip += ":";
- ip += _appHost.EnableHttps ? _config.Configuration.PublicHttpsPort.ToString(CultureInfo.InvariantCulture) : _config.Configuration.PublicPort.ToString(CultureInfo.InvariantCulture);
-
- return ip;
- }
-
- return null;
- }
- }
-
- private string XApplicationValue
- {
- get { return _appHost.Name + "/" + _appHost.ApplicationVersion; }
- }
-
- public ConnectManager(ILogger logger,
- IApplicationPaths appPaths,
- IJsonSerializer json,
- IEncryptionManager encryption,
- IHttpClient httpClient,
- IServerApplicationHost appHost,
- IServerConfigurationManager config, IUserManager userManager, IProviderManager providerManager, ISecurityManager securityManager, IFileSystem fileSystem)
- {
- _logger = logger;
- _appPaths = appPaths;
- _json = json;
- _encryption = encryption;
- _httpClient = httpClient;
- _appHost = appHost;
- _config = config;
- _userManager = userManager;
- _providerManager = providerManager;
- _securityManager = securityManager;
- _fileSystem = fileSystem;
-
- LoadCachedData();
- }
-
- internal void Start()
- {
- _config.ConfigurationUpdated += _config_ConfigurationUpdated;
- }
-
- internal void OnWanAddressResolved(IpAddressInfo address)
- {
- DiscoveredWanIpAddress = address;
-
- var task = UpdateConnectInfo();
- }
-
- private async Task UpdateConnectInfo()
- {
- await _operationLock.WaitAsync().ConfigureAwait(false);
-
- try
- {
- await UpdateConnectInfoInternal().ConfigureAwait(false);
- }
- finally
- {
- _operationLock.Release();
- }
- }
-
- private async Task UpdateConnectInfoInternal()
- {
- var wanApiAddress = WanApiAddress;
-
- if (string.IsNullOrWhiteSpace(wanApiAddress))
- {
- _logger.Warn("Cannot update Emby Connect information without a WanApiAddress");
- return;
- }
-
- try
- {
- var localAddress = await _appHost.GetLocalApiUrl().ConfigureAwait(false);
-
- var hasExistingRecord = !string.IsNullOrWhiteSpace(ConnectServerId) &&
- !string.IsNullOrWhiteSpace(ConnectAccessKey);
-
- var createNewRegistration = !hasExistingRecord;
-
- if (hasExistingRecord)
- {
- try
- {
- await UpdateServerRegistration(wanApiAddress, localAddress).ConfigureAwait(false);
- }
- catch (HttpException ex)
- {
- if (!ex.StatusCode.HasValue || !new[] { HttpStatusCode.NotFound, HttpStatusCode.Unauthorized }.Contains(ex.StatusCode.Value))
- {
- throw;
- }
-
- createNewRegistration = true;
- }
- }
-
- if (createNewRegistration)
- {
- await CreateServerRegistration(wanApiAddress, localAddress).ConfigureAwait(false);
- }
-
- _lastReportedIdentifier = GetConnectReportingIdentifier(localAddress, wanApiAddress);
-
- await RefreshAuthorizationsInternal(true, CancellationToken.None).ConfigureAwait(false);
- }
- catch (Exception ex)
- {
- _logger.ErrorException("Error registering with Connect", ex);
- }
- }
-
- private string _lastReportedIdentifier;
- private async Task GetConnectReportingIdentifier()
- {
- var url = await _appHost.GetLocalApiUrl().ConfigureAwait(false);
- return GetConnectReportingIdentifier(url, WanApiAddress);
- }
- private string GetConnectReportingIdentifier(string localAddress, string remoteAddress)
- {
- return (remoteAddress ?? string.Empty) + (localAddress ?? string.Empty);
- }
-
- async void _config_ConfigurationUpdated(object sender, EventArgs e)
- {
- // If info hasn't changed, don't report anything
- var connectIdentifier = await GetConnectReportingIdentifier().ConfigureAwait(false);
- if (string.Equals(_lastReportedIdentifier, connectIdentifier, StringComparison.OrdinalIgnoreCase))
- {
- return;
- }
-
- await UpdateConnectInfo().ConfigureAwait(false);
- }
-
- private async Task CreateServerRegistration(string wanApiAddress, string localAddress)
- {
- if (string.IsNullOrWhiteSpace(wanApiAddress))
- {
- throw new ArgumentNullException("wanApiAddress");
- }
-
- var url = "Servers";
- url = GetConnectUrl(url);
-
- var postData = new Dictionary
- {
- {"name", _appHost.FriendlyName},
- {"url", wanApiAddress},
- {"systemId", _appHost.SystemId}
- };
-
- if (!string.IsNullOrWhiteSpace(localAddress))
- {
- postData["localAddress"] = localAddress;
- }
-
- var options = new HttpRequestOptions
- {
- Url = url,
- CancellationToken = CancellationToken.None,
- BufferContent = false
- };
-
- options.SetPostData(postData);
- SetApplicationHeader(options);
-
- using (var response = await _httpClient.Post(options).ConfigureAwait(false))
- {
- var data = _json.DeserializeFromStream(response.Content);
-
- _data.ServerId = data.Id;
- _data.AccessKey = data.AccessKey;
-
- CacheData();
- }
- }
-
- private async Task UpdateServerRegistration(string wanApiAddress, string localAddress)
- {
- if (string.IsNullOrWhiteSpace(wanApiAddress))
- {
- throw new ArgumentNullException("wanApiAddress");
- }
-
- if (string.IsNullOrWhiteSpace(ConnectServerId))
- {
- throw new ArgumentNullException("ConnectServerId");
- }
-
- var url = "Servers";
- url = GetConnectUrl(url);
- url += "?id=" + ConnectServerId;
-
- var postData = new Dictionary
- {
- {"name", _appHost.FriendlyName},
- {"url", wanApiAddress},
- {"systemId", _appHost.SystemId}
- };
-
- if (!string.IsNullOrWhiteSpace(localAddress))
- {
- postData["localAddress"] = localAddress;
- }
-
- var options = new HttpRequestOptions
- {
- Url = url,
- CancellationToken = CancellationToken.None,
- BufferContent = false
- };
-
- options.SetPostData(postData);
-
- SetServerAccessToken(options);
- SetApplicationHeader(options);
-
- // No need to examine the response
- using (var stream = (await _httpClient.Post(options).ConfigureAwait(false)).Content)
- {
- }
- }
-
- private readonly object _dataFileLock = new object();
- private string CacheFilePath
- {
- get { return Path.Combine(_appPaths.DataPath, "connect.txt"); }
- }
-
- private void CacheData()
- {
- var path = CacheFilePath;
-
- try
- {
- _fileSystem.CreateDirectory(Path.GetDirectoryName(path));
-
- var json = _json.SerializeToString(_data);
-
- var encrypted = _encryption.EncryptString(json);
-
- lock (_dataFileLock)
- {
- _fileSystem.WriteAllText(path, encrypted, Encoding.UTF8);
- }
- }
- catch (Exception ex)
- {
- _logger.ErrorException("Error saving data", ex);
- }
- }
-
- private void LoadCachedData()
- {
- var path = CacheFilePath;
-
- _logger.Info("Loading data from {0}", path);
-
- try
- {
- lock (_dataFileLock)
- {
- var encrypted = _fileSystem.ReadAllText(path, Encoding.UTF8);
-
- var json = _encryption.DecryptString(encrypted);
-
- _data = _json.DeserializeFromString(json);
- }
- }
- catch (IOException)
- {
- // File isn't there. no biggie
- }
- catch (Exception ex)
- {
- _logger.ErrorException("Error loading data", ex);
- }
- }
-
- private User GetUser(string id)
- {
- var user = _userManager.GetUserById(id);
-
- if (user == null)
- {
- throw new ArgumentException("User not found.");
- }
-
- return user;
- }
-
- private string GetConnectUrl(string handler)
- {
- return "https://connect.emby.media/service/" + handler;
- }
-
- public async Task LinkUser(string userId, string connectUsername)
- {
- if (string.IsNullOrWhiteSpace(userId))
- {
- throw new ArgumentNullException("userId");
- }
- if (string.IsNullOrWhiteSpace(connectUsername))
- {
- throw new ArgumentNullException("connectUsername");
- }
- if (string.IsNullOrWhiteSpace(ConnectServerId))
- {
- await UpdateConnectInfo().ConfigureAwait(false);
- }
-
- await _operationLock.WaitAsync().ConfigureAwait(false);
-
- try
- {
- return await LinkUserInternal(userId, connectUsername).ConfigureAwait(false);
- }
- finally
- {
- _operationLock.Release();
- }
- }
-
- private async Task LinkUserInternal(string userId, string connectUsername)
- {
- if (string.IsNullOrWhiteSpace(ConnectServerId))
- {
- throw new ArgumentNullException("ConnectServerId");
- }
-
- var connectUser = await GetConnectUser(new ConnectUserQuery
- {
- NameOrEmail = connectUsername
-
- }, CancellationToken.None).ConfigureAwait(false);
-
- if (!connectUser.IsActive)
- {
- throw new ArgumentException("The Emby account has been disabled.");
- }
-
- var existingUser = _userManager.Users.FirstOrDefault(i => string.Equals(i.ConnectUserId, connectUser.Id) && !string.IsNullOrWhiteSpace(i.ConnectAccessKey));
- if (existingUser != null)
- {
- throw new InvalidOperationException("This connect user is already linked to local user " + existingUser.Name);
- }
-
- var user = GetUser(userId);
-
- if (!string.IsNullOrWhiteSpace(user.ConnectUserId))
- {
- await RemoveConnect(user, user.ConnectUserId).ConfigureAwait(false);
- }
-
- var url = GetConnectUrl("ServerAuthorizations");
-
- var options = new HttpRequestOptions
- {
- Url = url,
- CancellationToken = CancellationToken.None,
- BufferContent = false
- };
-
- var accessToken = Guid.NewGuid().ToString("N");
-
- var postData = new Dictionary
- {
- {"serverId", ConnectServerId},
- {"userId", connectUser.Id},
- {"userType", "Linked"},
- {"accessToken", accessToken}
- };
-
- options.SetPostData(postData);
-
- SetServerAccessToken(options);
- SetApplicationHeader(options);
-
- var result = new UserLinkResult();
-
- // No need to examine the response
- using (var stream = (await _httpClient.Post(options).ConfigureAwait(false)).Content)
- {
- var response = _json.DeserializeFromStream(stream);
-
- result.IsPending = string.Equals(response.AcceptStatus, "waiting", StringComparison.OrdinalIgnoreCase);
- }
-
- user.ConnectAccessKey = accessToken;
- user.ConnectUserName = connectUser.Name;
- user.ConnectUserId = connectUser.Id;
- user.ConnectLinkType = UserLinkType.LinkedUser;
-
- await user.UpdateToRepository(ItemUpdateType.MetadataEdit, CancellationToken.None).ConfigureAwait(false);
-
- await _userManager.UpdateConfiguration(user.Id.ToString("N"), user.Configuration);
-
- await RefreshAuthorizationsInternal(false, CancellationToken.None).ConfigureAwait(false);
-
- return result;
- }
-
- public async Task InviteUser(ConnectAuthorizationRequest request)
- {
- if (string.IsNullOrWhiteSpace(ConnectServerId))
- {
- await UpdateConnectInfo().ConfigureAwait(false);
- }
-
- await _operationLock.WaitAsync().ConfigureAwait(false);
-
- try
- {
- return await InviteUserInternal(request).ConfigureAwait(false);
- }
- finally
- {
- _operationLock.Release();
- }
- }
-
- private async Task InviteUserInternal(ConnectAuthorizationRequest request)
- {
- var connectUsername = request.ConnectUserName;
- var sendingUserId = request.SendingUserId;
-
- if (string.IsNullOrWhiteSpace(connectUsername))
- {
- throw new ArgumentNullException("connectUsername");
- }
- if (string.IsNullOrWhiteSpace(ConnectServerId))
- {
- throw new ArgumentNullException("ConnectServerId");
- }
-
- var sendingUser = GetUser(sendingUserId);
- var requesterUserName = sendingUser.ConnectUserName;
-
- if (string.IsNullOrWhiteSpace(requesterUserName))
- {
- throw new ArgumentException("A Connect account is required in order to send invitations.");
- }
-
- string connectUserId = null;
- var result = new UserLinkResult();
-
- try
- {
- var connectUser = await GetConnectUser(new ConnectUserQuery
- {
- NameOrEmail = connectUsername
-
- }, CancellationToken.None).ConfigureAwait(false);
-
- if (!connectUser.IsActive)
- {
- throw new ArgumentException("The Emby account is not active. Please ensure the account has been activated by following the instructions within the email confirmation.");
- }
-
- connectUserId = connectUser.Id;
- result.GuestDisplayName = connectUser.Name;
- }
- catch (HttpException ex)
- {
- if (!ex.StatusCode.HasValue || ex.IsTimedOut)
- {
- throw new Exception("Unable to invite guest, " + ex.Message, ex);
- }
-
- // If they entered a username, then whatever the error is just throw it, for example, user not found
- if (!Validator.EmailIsValid(connectUsername))
- {
- if (ex.StatusCode.Value == HttpStatusCode.NotFound)
- {
- throw new ResourceNotFoundException();
- }
- throw;
- }
-
- if (ex.StatusCode.Value != HttpStatusCode.NotFound)
- {
- throw;
- }
- }
-
- if (string.IsNullOrWhiteSpace(connectUserId))
- {
- return await SendNewUserInvitation(requesterUserName, connectUsername).ConfigureAwait(false);
- }
-
- var url = GetConnectUrl("ServerAuthorizations");
-
- var options = new HttpRequestOptions
- {
- Url = url,
- CancellationToken = CancellationToken.None,
- BufferContent = false
- };
-
- var accessToken = Guid.NewGuid().ToString("N");
-
- var postData = new Dictionary
- {
- {"serverId", ConnectServerId},
- {"userId", connectUserId},
- {"userType", "Guest"},
- {"accessToken", accessToken},
- {"requesterUserName", requesterUserName}
- };
-
- options.SetPostData(postData);
-
- SetServerAccessToken(options);
- SetApplicationHeader(options);
-
- // No need to examine the response
- using (var stream = (await _httpClient.Post(options).ConfigureAwait(false)).Content)
- {
- var response = _json.DeserializeFromStream(stream);
-
- result.IsPending = string.Equals(response.AcceptStatus, "waiting", StringComparison.OrdinalIgnoreCase);
-
- _data.PendingAuthorizations.Add(new ConnectAuthorizationInternal
- {
- ConnectUserId = response.UserId,
- Id = response.Id,
- ImageUrl = response.UserImageUrl,
- UserName = response.UserName,
- EnabledLibraries = request.EnabledLibraries,
- EnabledChannels = request.EnabledChannels,
- EnableLiveTv = request.EnableLiveTv,
- AccessToken = accessToken
- });
-
- CacheData();
- }
-
- await RefreshAuthorizationsInternal(false, CancellationToken.None).ConfigureAwait(false);
-
- return result;
- }
-
- private async Task SendNewUserInvitation(string fromName, string email)
- {
- var url = GetConnectUrl("users/invite");
-
- var options = new HttpRequestOptions
- {
- Url = url,
- CancellationToken = CancellationToken.None,
- BufferContent = false
- };
-
- var postData = new Dictionary
- {
- {"email", email},
- {"requesterUserName", fromName}
- };
-
- options.SetPostData(postData);
- SetApplicationHeader(options);
-
- // No need to examine the response
- using (var stream = (await _httpClient.Post(options).ConfigureAwait(false)).Content)
- {
- }
-
- return new UserLinkResult
- {
- IsNewUserInvitation = true,
- GuestDisplayName = email
- };
- }
-
- public Task RemoveConnect(string userId)
- {
- var user = GetUser(userId);
-
- return RemoveConnect(user, user.ConnectUserId);
- }
-
- private async Task RemoveConnect(User user, string connectUserId)
- {
- if (!string.IsNullOrWhiteSpace(connectUserId))
- {
- await CancelAuthorizationByConnectUserId(connectUserId).ConfigureAwait(false);
- }
-
- user.ConnectAccessKey = null;
- user.ConnectUserName = null;
- user.ConnectUserId = null;
- user.ConnectLinkType = null;
-
- await user.UpdateToRepository(ItemUpdateType.MetadataEdit, CancellationToken.None).ConfigureAwait(false);
- }
-
- private async Task GetConnectUser(ConnectUserQuery query, CancellationToken cancellationToken)
- {
- var url = GetConnectUrl("user");
-
- if (!string.IsNullOrWhiteSpace(query.Id))
- {
- url = url + "?id=" + WebUtility.UrlEncode(query.Id);
- }
- else if (!string.IsNullOrWhiteSpace(query.NameOrEmail))
- {
- url = url + "?nameOrEmail=" + WebUtility.UrlEncode(query.NameOrEmail);
- }
- else if (!string.IsNullOrWhiteSpace(query.Name))
- {
- url = url + "?name=" + WebUtility.UrlEncode(query.Name);
- }
- else if (!string.IsNullOrWhiteSpace(query.Email))
- {
- url = url + "?name=" + WebUtility.UrlEncode(query.Email);
- }
- else
- {
- throw new ArgumentException("Empty ConnectUserQuery supplied");
- }
-
- var options = new HttpRequestOptions
- {
- CancellationToken = cancellationToken,
- Url = url,
- BufferContent = false
- };
-
- SetServerAccessToken(options);
- SetApplicationHeader(options);
-
- using (var stream = await _httpClient.Get(options).ConfigureAwait(false))
- {
- var response = _json.DeserializeFromStream(stream);
-
- return new ConnectUser
- {
- Email = response.Email,
- Id = response.Id,
- Name = response.Name,
- IsActive = response.IsActive,
- ImageUrl = response.ImageUrl
- };
- }
- }
-
- private void SetApplicationHeader(HttpRequestOptions options)
- {
- options.RequestHeaders.Add("X-Application", XApplicationValue);
- }
-
- private void SetServerAccessToken(HttpRequestOptions options)
- {
- if (string.IsNullOrWhiteSpace(ConnectAccessKey))
- {
- throw new ArgumentNullException("ConnectAccessKey");
- }
-
- options.RequestHeaders.Add("X-Connect-Token", ConnectAccessKey);
- }
-
- public async Task RefreshAuthorizations(CancellationToken cancellationToken)
- {
- await _operationLock.WaitAsync(cancellationToken).ConfigureAwait(false);
-
- try
- {
- await RefreshAuthorizationsInternal(true, cancellationToken).ConfigureAwait(false);
- }
- finally
- {
- _operationLock.Release();
- }
- }
-
- private async Task RefreshAuthorizationsInternal(bool refreshImages, CancellationToken cancellationToken)
- {
- if (string.IsNullOrWhiteSpace(ConnectServerId))
- {
- throw new ArgumentNullException("ConnectServerId");
- }
-
- var url = GetConnectUrl("ServerAuthorizations");
-
- url += "?serverId=" + ConnectServerId;
-
- var options = new HttpRequestOptions
- {
- Url = url,
- CancellationToken = cancellationToken,
- BufferContent = false
- };
-
- SetServerAccessToken(options);
- SetApplicationHeader(options);
-
- try
- {
- using (var stream = (await _httpClient.SendAsync(options, "GET").ConfigureAwait(false)).Content)
- {
- var list = _json.DeserializeFromStream>(stream);
-
- await RefreshAuthorizations(list, refreshImages).ConfigureAwait(false);
- }
- }
- catch (Exception ex)
- {
- _logger.ErrorException("Error refreshing server authorizations.", ex);
- }
- }
-
- private async Task RefreshAuthorizations(List list, bool refreshImages)
- {
- var users = _userManager.Users.ToList();
-
- // Handle existing authorizations that were removed by the Connect server
- // Handle existing authorizations whose status may have been updated
- foreach (var user in users)
- {
- if (!string.IsNullOrWhiteSpace(user.ConnectUserId))
- {
- var connectEntry = list.FirstOrDefault(i => string.Equals(i.UserId, user.ConnectUserId, StringComparison.OrdinalIgnoreCase));
-
- if (connectEntry == null)
- {
- var deleteUser = user.ConnectLinkType.HasValue &&
- user.ConnectLinkType.Value == UserLinkType.Guest;
-
- user.ConnectUserId = null;
- user.ConnectAccessKey = null;
- user.ConnectUserName = null;
- user.ConnectLinkType = null;
-
- await _userManager.UpdateUser(user).ConfigureAwait(false);
-
- if (deleteUser)
- {
- _logger.Debug("Deleting guest user {0}", user.Name);
- await _userManager.DeleteUser(user).ConfigureAwait(false);
- }
- }
- else
- {
- var changed = !string.Equals(user.ConnectAccessKey, connectEntry.AccessToken, StringComparison.OrdinalIgnoreCase);
-
- if (changed)
- {
- user.ConnectUserId = connectEntry.UserId;
- user.ConnectAccessKey = connectEntry.AccessToken;
-
- await _userManager.UpdateUser(user).ConfigureAwait(false);
- }
- }
- }
- }
-
- var currentPendingList = _data.PendingAuthorizations.ToList();
- var newPendingList = new List();
-
- foreach (var connectEntry in list)
- {
- if (string.Equals(connectEntry.UserType, "guest", StringComparison.OrdinalIgnoreCase))
- {
- var currentPendingEntry = currentPendingList.FirstOrDefault(i => string.Equals(i.Id, connectEntry.Id, StringComparison.OrdinalIgnoreCase));
-
- if (string.Equals(connectEntry.AcceptStatus, "accepted", StringComparison.OrdinalIgnoreCase))
- {
- var user = _userManager.Users
- .FirstOrDefault(i => string.Equals(i.ConnectUserId, connectEntry.UserId, StringComparison.OrdinalIgnoreCase));
-
- if (user == null)
- {
- // Add user
- user = await _userManager.CreateUser(_userManager.MakeValidUsername(connectEntry.UserName)).ConfigureAwait(false);
-
- user.ConnectUserName = connectEntry.UserName;
- user.ConnectUserId = connectEntry.UserId;
- user.ConnectLinkType = UserLinkType.Guest;
- user.ConnectAccessKey = connectEntry.AccessToken;
-
- await _userManager.UpdateUser(user).ConfigureAwait(false);
-
- user.Policy.IsHidden = true;
- user.Policy.EnableLiveTvManagement = false;
- user.Policy.EnableContentDeletion = false;
- user.Policy.EnableRemoteControlOfOtherUsers = false;
- user.Policy.EnableSharedDeviceControl = false;
- user.Policy.IsAdministrator = false;
-
- if (currentPendingEntry != null)
- {
- user.Policy.EnabledFolders = currentPendingEntry.EnabledLibraries;
- user.Policy.EnableAllFolders = false;
-
- user.Policy.EnabledChannels = currentPendingEntry.EnabledChannels;
- user.Policy.EnableAllChannels = false;
-
- user.Policy.EnableLiveTvAccess = currentPendingEntry.EnableLiveTv;
- }
-
- await _userManager.UpdateConfiguration(user.Id.ToString("N"), user.Configuration);
- }
- }
- else if (string.Equals(connectEntry.AcceptStatus, "waiting", StringComparison.OrdinalIgnoreCase))
- {
- currentPendingEntry = currentPendingEntry ?? new ConnectAuthorizationInternal();
-
- currentPendingEntry.ConnectUserId = connectEntry.UserId;
- currentPendingEntry.ImageUrl = connectEntry.UserImageUrl;
- currentPendingEntry.UserName = connectEntry.UserName;
- currentPendingEntry.Id = connectEntry.Id;
- currentPendingEntry.AccessToken = connectEntry.AccessToken;
-
- newPendingList.Add(currentPendingEntry);
- }
- }
- }
-
- _data.PendingAuthorizations = newPendingList;
-
- if (!newPendingList.Select(i => i.Id).SequenceEqual(currentPendingList.Select(i => i.Id), StringComparer.Ordinal))
- {
- CacheData();
- }
-
- await RefreshGuestNames(list, refreshImages).ConfigureAwait(false);
- }
-
- private async Task RefreshGuestNames(List list, bool refreshImages)
- {
- var users = _userManager.Users
- .Where(i => !string.IsNullOrEmpty(i.ConnectUserId) && i.ConnectLinkType.HasValue && i.ConnectLinkType.Value == UserLinkType.Guest)
- .ToList();
-
- foreach (var user in users)
- {
- var authorization = list.FirstOrDefault(i => string.Equals(i.UserId, user.ConnectUserId, StringComparison.Ordinal));
-
- if (authorization == null)
- {
- _logger.Warn("Unable to find connect authorization record for user {0}", user.Name);
- continue;
- }
-
- var syncConnectName = true;
- var syncConnectImage = true;
-
- if (syncConnectName)
- {
- var changed = !string.Equals(authorization.UserName, user.Name, StringComparison.OrdinalIgnoreCase);
-
- if (changed)
- {
- await user.Rename(authorization.UserName).ConfigureAwait(false);
- }
- }
-
- if (syncConnectImage)
- {
- var imageUrl = authorization.UserImageUrl;
-
- if (!string.IsNullOrWhiteSpace(imageUrl))
- {
- var changed = false;
-
- if (!user.HasImage(ImageType.Primary))
- {
- changed = true;
- }
- else if (refreshImages)
- {
- using (var response = await _httpClient.SendAsync(new HttpRequestOptions
- {
- Url = imageUrl,
- BufferContent = false
-
- }, "HEAD").ConfigureAwait(false))
- {
- var length = response.ContentLength;
-
- if (length != _fileSystem.GetFileInfo(user.GetImageInfo(ImageType.Primary, 0).Path).Length)
- {
- changed = true;
- }
- }
- }
-
- if (changed)
- {
- await _providerManager.SaveImage(user, imageUrl, ImageType.Primary, null, CancellationToken.None).ConfigureAwait(false);
-
- await user.RefreshMetadata(new MetadataRefreshOptions(_fileSystem)
- {
- ForceSave = true,
-
- }, CancellationToken.None).ConfigureAwait(false);
- }
- }
- }
- }
- }
-
- public async Task> GetPendingGuests()
- {
- var time = DateTime.UtcNow - _data.LastAuthorizationsRefresh;
-
- if (time.TotalMinutes >= 5)
- {
- await _operationLock.WaitAsync(CancellationToken.None).ConfigureAwait(false);
-
- try
- {
- await RefreshAuthorizationsInternal(false, CancellationToken.None).ConfigureAwait(false);
-
- _data.LastAuthorizationsRefresh = DateTime.UtcNow;
- CacheData();
- }
- catch (Exception ex)
- {
- _logger.ErrorException("Error refreshing authorization", ex);
- }
- finally
- {
- _operationLock.Release();
- }
- }
-
- return _data.PendingAuthorizations.Select(i => new ConnectAuthorization
- {
- ConnectUserId = i.ConnectUserId,
- EnableLiveTv = i.EnableLiveTv,
- EnabledChannels = i.EnabledChannels,
- EnabledLibraries = i.EnabledLibraries,
- Id = i.Id,
- ImageUrl = i.ImageUrl,
- UserName = i.UserName
-
- }).ToList();
- }
-
- public async Task CancelAuthorization(string id)
- {
- await _operationLock.WaitAsync().ConfigureAwait(false);
-
- try
- {
- await CancelAuthorizationInternal(id).ConfigureAwait(false);
- }
- finally
- {
- _operationLock.Release();
- }
- }
-
- private async Task CancelAuthorizationInternal(string id)
- {
- var connectUserId = _data.PendingAuthorizations
- .First(i => string.Equals(i.Id, id, StringComparison.Ordinal))
- .ConnectUserId;
-
- await CancelAuthorizationByConnectUserId(connectUserId).ConfigureAwait(false);
-
- await RefreshAuthorizationsInternal(false, CancellationToken.None).ConfigureAwait(false);
- }
-
- private async Task CancelAuthorizationByConnectUserId(string connectUserId)
- {
- if (string.IsNullOrWhiteSpace(connectUserId))
- {
- throw new ArgumentNullException("connectUserId");
- }
- if (string.IsNullOrWhiteSpace(ConnectServerId))
- {
- throw new ArgumentNullException("ConnectServerId");
- }
-
- var url = GetConnectUrl("ServerAuthorizations");
-
- var options = new HttpRequestOptions
- {
- Url = url,
- CancellationToken = CancellationToken.None,
- BufferContent = false
- };
-
- var postData = new Dictionary
- {
- {"serverId", ConnectServerId},
- {"userId", connectUserId}
- };
-
- options.SetPostData(postData);
-
- SetServerAccessToken(options);
- SetApplicationHeader(options);
-
- try
- {
- // No need to examine the response
- using (var stream = (await _httpClient.SendAsync(options, "DELETE").ConfigureAwait(false)).Content)
- {
- }
- }
- catch (HttpException ex)
- {
- // If connect says the auth doesn't exist, we can handle that gracefully since this is a remove operation
-
- if (!ex.StatusCode.HasValue || ex.StatusCode.Value != HttpStatusCode.NotFound)
- {
- throw;
- }
-
- _logger.Debug("Connect returned a 404 when removing a user auth link. Handling it.");
- }
- }
-
- public async Task Authenticate(string username, string passwordMd5)
- {
- if (string.IsNullOrWhiteSpace(username))
- {
- throw new ArgumentNullException("username");
- }
-
- if (string.IsNullOrWhiteSpace(passwordMd5))
- {
- throw new ArgumentNullException("passwordMd5");
- }
-
- var options = new HttpRequestOptions
- {
- Url = GetConnectUrl("user/authenticate"),
- BufferContent = false
- };
-
- options.SetPostData(new Dictionary
- {
- {"userName",username},
- {"password",passwordMd5}
- });
-
- SetApplicationHeader(options);
-
- // No need to examine the response
- using (var response = (await _httpClient.SendAsync(options, "POST").ConfigureAwait(false)).Content)
- {
- return _json.DeserializeFromStream(response);
- }
- }
-
- public async Task GetLocalUser(string connectUserId)
- {
- var user = _userManager.Users
- .FirstOrDefault(i => string.Equals(i.ConnectUserId, connectUserId, StringComparison.OrdinalIgnoreCase));
-
- if (user == null)
- {
- await RefreshAuthorizations(CancellationToken.None).ConfigureAwait(false);
- }
-
- return _userManager.Users
- .FirstOrDefault(i => string.Equals(i.ConnectUserId, connectUserId, StringComparison.OrdinalIgnoreCase));
- }
-
- public User GetUserFromExchangeToken(string token)
- {
- if (string.IsNullOrWhiteSpace(token))
- {
- throw new ArgumentNullException("token");
- }
-
- return _userManager.Users.FirstOrDefault(u => string.Equals(token, u.ConnectAccessKey, StringComparison.OrdinalIgnoreCase));
- }
-
- public bool IsAuthorizationTokenValid(string token)
- {
- if (string.IsNullOrWhiteSpace(token))
- {
- throw new ArgumentNullException("token");
- }
-
- return _userManager.Users.Any(u => string.Equals(token, u.ConnectAccessKey, StringComparison.OrdinalIgnoreCase)) ||
- _data.PendingAuthorizations.Select(i => i.AccessToken).Contains(token, StringComparer.OrdinalIgnoreCase);
- }
- }
-}
diff --git a/Emby.Server.Implementations/Connect/Responses.cs b/Emby.Server.Implementations/Connect/Responses.cs
deleted file mode 100644
index 87cb6cdf9..000000000
--- a/Emby.Server.Implementations/Connect/Responses.cs
+++ /dev/null
@@ -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
- {
- public T data { get; set; }
- }
-
- public class ConnectAuthorizationInternal : ConnectAuthorization
- {
- public string AccessToken { get; set; }
- }
-}
diff --git a/Emby.Server.Implementations/Connect/Validator.cs b/Emby.Server.Implementations/Connect/Validator.cs
deleted file mode 100644
index 5c94fa71c..000000000
--- a/Emby.Server.Implementations/Connect/Validator.cs
+++ /dev/null
@@ -1,29 +0,0 @@
-using System.Text.RegularExpressions;
-
-namespace Emby.Server.Implementations.Connect
-{
- public static class Validator
- {
- static readonly Regex ValidEmailRegex = CreateValidEmailRegex();
-
- ///
- /// Taken from http://haacked.com/archive/2007/08/21/i-knew-how-to-validate-an-email-address-until-i.aspx
- ///
- ///
- private static Regex CreateValidEmailRegex()
- {
- const string validEmailPattern = @"^(?!\.)(""([^""\r\\]|\\[""\r\\])*""|"
- + @"([-a-z0-9!#$%&'*+/=?^_`{|}~]|(?("IsFavorite", true);
+ // (Select Case When Abs(COALESCE(ProductionYear, 0) - @ItemProductionYear) < 10 Then 2 Else 0 End )
+ return new Tuple("(Select Case When IsFavorite is null Then 0 Else IsFavorite End )", true);
}
if (string.Equals(name, ItemSortBy.IsFolder, StringComparison.OrdinalIgnoreCase))
{
@@ -3874,6 +3875,25 @@ namespace Emby.Server.Implementations.Data
whereClauses.Add(clause);
}
+ if (query.AlbumIds.Length > 0)
+ {
+ var clauses = new List();
+ var index = 0;
+ foreach (var albumId in query.AlbumIds)
+ {
+ var paramName = "@AlbumIds" + index;
+
+ clauses.Add("Album in (select Name from typedbaseitems where guid=" + paramName + ")");
+ if (statement != null)
+ {
+ statement.TryBind(paramName, albumId.ToGuidParamValue());
+ }
+ index++;
+ }
+ var clause = "(" + string.Join(" OR ", clauses.ToArray()) + ")";
+ whereClauses.Add(clause);
+ }
+
if (query.ExcludeArtistIds.Length > 0)
{
var clauses = new List();
@@ -4227,30 +4247,6 @@ namespace Emby.Server.Implementations.Data
{
whereClauses.Add("ProviderIds like '%tvdb=%'");
}
-
- if (query.AlbumNames.Length > 0)
- {
- var clause = "(";
-
- var index = 0;
- foreach (var name in query.AlbumNames)
- {
- if (index > 0)
- {
- clause += " OR ";
- }
- clause += "Album=@AlbumName" + index;
-
- if (statement != null)
- {
- statement.TryBind("@AlbumName" + index, name);
- }
- index++;
- }
-
- clause += ")";
- whereClauses.Add(clause);
- }
if (query.HasThemeSong.HasValue)
{
if (query.HasThemeSong.Value)
diff --git a/Emby.Server.Implementations/Dto/DtoService.cs b/Emby.Server.Implementations/Dto/DtoService.cs
index 9c50ad5da..4ee3df7f5 100644
--- a/Emby.Server.Implementations/Dto/DtoService.cs
+++ b/Emby.Server.Implementations/Dto/DtoService.cs
@@ -360,7 +360,6 @@ namespace Emby.Server.Implementations.Dto
var collectionFolder = item as ICollectionFolder;
if (collectionFolder != null)
{
- dto.OriginalCollectionType = collectionFolder.CollectionType;
dto.CollectionType = collectionFolder.CollectionType;
}
@@ -492,7 +491,10 @@ namespace Emby.Server.Implementations.Dto
}
}
- dto.PlayAccess = item.GetPlayAccess(user);
+ //if (!(item is LiveTvProgram))
+ {
+ dto.PlayAccess = item.GetPlayAccess(user);
+ }
if (fields.Contains(ItemFields.BasicSyncInfo) || fields.Contains(ItemFields.SyncInfo))
{
@@ -502,33 +504,6 @@ namespace Emby.Server.Implementations.Dto
dto.SupportsSync = true;
}
}
-
- if (fields.Contains(ItemFields.SeasonUserData))
- {
- var episode = item as Episode;
-
- if (episode != null)
- {
- var season = episode.Season;
-
- if (season != null)
- {
- dto.SeasonUserData = await _userDataRepository.GetUserDataDto(season, user).ConfigureAwait(false);
- }
- }
- }
-
- var userView = item as UserView;
- if (userView != null)
- {
- dto.HasDynamicCategories = userView.ContainsDynamicCategories(user);
- }
-
- var collectionFolder = item as ICollectionFolder;
- if (collectionFolder != null)
- {
- dto.HasDynamicCategories = false;
- }
}
private int GetChildCount(Folder folder, User user)
@@ -879,20 +854,6 @@ namespace Emby.Server.Implementations.Dto
}
dto.Container = item.Container;
- var hasBudget = item as IHasBudget;
- if (hasBudget != null)
- {
- if (fields.Contains(ItemFields.Budget))
- {
- dto.Budget = hasBudget.Budget;
- }
-
- if (fields.Contains(ItemFields.Revenue))
- {
- dto.Revenue = hasBudget.Revenue;
- }
- }
-
dto.EndDate = item.EndDate;
if (fields.Contains(ItemFields.HomePageUrl))
@@ -994,7 +955,12 @@ namespace Emby.Server.Implementations.Dto
}
dto.MediaType = item.MediaType;
- dto.LocationType = item.LocationType;
+
+ if (!(item is LiveTvProgram))
+ {
+ dto.LocationType = item.LocationType;
+ }
+
if (item.IsHD.HasValue && item.IsHD.Value)
{
dto.IsHD = item.IsHD;
@@ -1065,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;
@@ -1102,7 +1068,10 @@ namespace Emby.Server.Implementations.Dto
}
dto.Type = item.GetClientTypeName();
- dto.CommunityRating = item.CommunityRating;
+ if ((item.CommunityRating ?? 0) > 0)
+ {
+ dto.CommunityRating = item.CommunityRating;
+ }
if (fields.Contains(ItemFields.VoteCount))
{
@@ -1396,7 +1365,7 @@ namespace Emby.Server.Implementations.Dto
}
catch (Exception ex)
{
-
+
}
}
}
@@ -1409,9 +1378,7 @@ namespace Emby.Server.Implementations.Dto
{
dto.AirDays = series.AirDays;
dto.AirTime = series.AirTime;
- dto.SeriesStatus = series.Status;
-
- dto.AnimeSeriesIndex = series.AnimeSeriesIndex;
+ dto.Status = series.Status.HasValue ? series.Status.Value.ToString() : null;
}
// Add SeasonInfo
@@ -1473,9 +1440,12 @@ namespace Emby.Server.Implementations.Dto
SetBookProperties(dto, book);
}
- if (item.ProductionLocations.Count > 0 || item is Movie)
+ if (fields.Contains(ItemFields.ProductionLocations))
{
- dto.ProductionLocations = item.ProductionLocations.ToArray();
+ if (item.ProductionLocations.Count > 0 || item is Movie)
+ {
+ dto.ProductionLocations = item.ProductionLocations.ToArray();
+ }
}
var photo = item as Photo;
@@ -1596,7 +1566,7 @@ namespace Emby.Server.Implementations.Dto
}
}
- private string GetMappedPath(BaseItem item)
+ private string GetMappedPath(BaseItem item, BaseItem ownerItem)
{
var path = item.Path;
@@ -1604,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;
@@ -1630,8 +1600,20 @@ namespace Emby.Server.Implementations.Dto
return null;
}
+ var supportedEnhancers = _imageProcessor.GetSupportedEnhancers(item, ImageType.Primary).ToList();
+
ImageSize size;
+ if (supportedEnhancers.Count == 0)
+ {
+ var defaultAspectRatio = item.GetDefaultPrimaryImageAspectRatio();
+
+ if (defaultAspectRatio.HasValue)
+ {
+ return defaultAspectRatio.Value;
+ }
+ }
+
try
{
size = _imageProcessor.GetImageSize(imageInfo);
@@ -1642,8 +1624,6 @@ namespace Emby.Server.Implementations.Dto
return null;
}
- var supportedEnhancers = _imageProcessor.GetSupportedEnhancers(item, ImageType.Primary).ToList();
-
foreach (var enhancer in supportedEnhancers)
{
try
diff --git a/Emby.Server.Implementations/Emby.Server.Implementations.csproj b/Emby.Server.Implementations/Emby.Server.Implementations.csproj
index a1bd67f1f..13efb7bf9 100644
--- a/Emby.Server.Implementations/Emby.Server.Implementations.csproj
+++ b/Emby.Server.Implementations/Emby.Server.Implementations.csproj
@@ -35,6 +35,9 @@
+
+
+
@@ -46,11 +49,7 @@
-
-
-
-
-
+
@@ -179,6 +178,7 @@
+
@@ -213,8 +213,19 @@
+
+
+
+
+
+
+
+
+
+
+
@@ -253,23 +264,6 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
@@ -301,16 +295,12 @@
{2e781478-814d-4a48-9d80-bff206441a65}
MediaBrowser.Server.Implementations
-
- {680a1709-25eb-4d52-a87f-ee03ffd94baa}
- ServiceStack
-
{4f26d5d8-a7b0-42b3-ba42-7cb7d245934e}
SocketHttpListener.Portable
-
- ..\packages\Emby.XmlTv.1.0.6\lib\portable-net45+win8\Emby.XmlTv.dll
+
+ ..\packages\Emby.XmlTv.1.0.7\lib\portable-net45+win8\Emby.XmlTv.dll
True
@@ -322,7 +312,7 @@
True
- ..\packages\SQLitePCLRaw.core.1.1.1\lib\portable-net45+netcore45+wpa81+MonoAndroid10+MonoTouch10+Xamarin.iOS10\SQLitePCLRaw.core.dll
+ ..\packages\SQLitePCLRaw.core.1.1.2\lib\portable-net45+netcore45+wpa81+MonoAndroid10+MonoTouch10+Xamarin.iOS10\SQLitePCLRaw.core.dll
True
diff --git a/Emby.Server.Implementations/EntryPoints/UsageReporter.cs b/Emby.Server.Implementations/EntryPoints/UsageReporter.cs
index 31254c6c2..778c8a6ce 100644
--- a/Emby.Server.Implementations/EntryPoints/UsageReporter.cs
+++ b/Emby.Server.Implementations/EntryPoints/UsageReporter.cs
@@ -40,8 +40,7 @@ namespace Emby.Server.Implementations.EntryPoints
{ "serverid", _applicationHost.SystemId },
{ "deviceid", _applicationHost.SystemId },
{ "ver", _applicationHost.ApplicationVersion.ToString() },
- { "platform", _applicationHost.OperatingSystemDisplayName },
- { "isservice", _applicationHost.IsRunningAsService.ToString().ToLower()}
+ { "platform", _applicationHost.OperatingSystemDisplayName }
};
var users = _userManager.Users.ToList();
diff --git a/Emby.Server.Implementations/HttpServer/HttpListenerHost.cs b/Emby.Server.Implementations/HttpServer/HttpListenerHost.cs
index 322cdf4f0..6fcdab874 100644
--- a/Emby.Server.Implementations/HttpServer/HttpListenerHost.cs
+++ b/Emby.Server.Implementations/HttpServer/HttpListenerHost.cs
@@ -2,8 +2,6 @@
using MediaBrowser.Controller.Configuration;
using MediaBrowser.Controller.Net;
using MediaBrowser.Model.Logging;
-using ServiceStack;
-using ServiceStack.Host;
using System;
using System.Collections.Generic;
using System.IO;
@@ -13,6 +11,7 @@ using System.Text;
using System.Threading.Tasks;
using Emby.Server.Implementations.HttpServer;
using Emby.Server.Implementations.HttpServer.SocketSharp;
+using Emby.Server.Implementations.Services;
using MediaBrowser.Common.Net;
using MediaBrowser.Common.Security;
using MediaBrowser.Controller;
@@ -29,7 +28,7 @@ using SocketHttpListener.Primitives;
namespace Emby.Server.Implementations.HttpServer
{
- public class HttpListenerHost : ServiceStackHost, IHttpServer
+ public class HttpListenerHost : IHttpServer, IDisposable
{
private string DefaultRedirectPath { get; set; }
@@ -61,13 +60,21 @@ namespace Emby.Server.Implementations.HttpServer
private readonly Func> _funcParseFn;
private readonly bool _enableDualModeSockets;
+ public List> RequestFilters { get; set; }
+ public List> ResponseFilters { get; set; }
+
+ private readonly Dictionary ServiceOperationsMap = new Dictionary();
+ public static HttpListenerHost Instance { get; protected set; }
+
public HttpListenerHost(IServerApplicationHost applicationHost,
ILogger logger,
IServerConfigurationManager config,
string serviceName,
string defaultRedirectPath, INetworkManager networkManager, IMemoryStreamFactory memoryStreamProvider, ITextEncoding textEncoding, ISocketFactory socketFactory, ICryptoProvider cryptoProvider, IJsonSerializer jsonSerializer, IXmlSerializer xmlSerializer, IEnvironmentInfo environment, ICertificate certificate, IStreamFactory streamFactory, Func> funcParseFn, bool enableDualModeSockets)
- : base(serviceName)
+ : base()
{
+ Instance = this;
+
_appHost = applicationHost;
DefaultRedirectPath = defaultRedirectPath;
_networkManager = networkManager;
@@ -85,6 +92,9 @@ namespace Emby.Server.Implementations.HttpServer
_config = config;
_logger = logger;
+
+ RequestFilters = new List>();
+ ResponseFilters = new List>();
}
public string GlobalResponse { get; set; }
@@ -99,18 +109,7 @@ namespace Emby.Server.Implementations.HttpServer
{typeof (ArgumentException), 400}
};
- public override void Configure()
- {
- var requestFilters = _appHost.GetExports().ToList();
- foreach (var filter in requestFilters)
- {
- GlobalRequestFilters.Add(filter.Filter);
- }
-
- GlobalResponseFilters.Add(new ResponseFilter(_logger).FilterResponse);
- }
-
- protected override ILogger Logger
+ protected ILogger Logger
{
get
{
@@ -118,32 +117,73 @@ namespace Emby.Server.Implementations.HttpServer
}
}
- public override T Resolve()
- {
- return _appHost.Resolve();
- }
-
- public override T TryResolve()
- {
- return _appHost.TryResolve();
- }
-
- public override object CreateInstance(Type type)
+ public object CreateInstance(Type type)
{
return _appHost.CreateInstance(type);
}
- protected override ServiceController CreateServiceController()
+ private ServiceController CreateServiceController()
{
var types = _restServices.Select(r => r.GetType()).ToArray();
return new ServiceController(() => types);
}
- public override ServiceStackHost Start(string listeningAtUrlBase)
+ ///
+ /// Applies the request filters. Returns whether or not the request has been handled
+ /// and no more processing should be done.
+ ///
+ ///
+ public void ApplyRequestFilters(IRequest req, IResponse res, object requestDto)
{
- StartListener();
- return this;
+ //Exec all RequestFilter attributes with Priority < 0
+ var attributes = GetRequestFilterAttributes(requestDto.GetType());
+ var i = 0;
+ for (; i < attributes.Length && attributes[i].Priority < 0; i++)
+ {
+ var attribute = attributes[i];
+ attribute.RequestFilter(req, res, requestDto);
+ }
+
+ //Exec global filters
+ foreach (var requestFilter in RequestFilters)
+ {
+ requestFilter(req, res, requestDto);
+ }
+
+ //Exec remaining RequestFilter attributes with Priority >= 0
+ for (; i < attributes.Length && attributes[i].Priority >= 0; i++)
+ {
+ var attribute = attributes[i];
+ attribute.RequestFilter(req, res, requestDto);
+ }
+ }
+
+ public Type GetServiceTypeByRequest(Type requestType)
+ {
+ Type serviceType;
+ ServiceOperationsMap.TryGetValue(requestType, out serviceType);
+ return serviceType;
+ }
+
+ public void AddServiceInfo(Type serviceType, Type requestType, Type responseType)
+ {
+ ServiceOperationsMap[requestType] = serviceType;
+ }
+
+ private IHasRequestFilter[] GetRequestFilterAttributes(Type requestDtoType)
+ {
+ var attributes = requestDtoType.GetTypeInfo().GetCustomAttributes(true).OfType().ToList();
+
+ var serviceType = GetServiceTypeByRequest(requestDtoType);
+ if (serviceType != null)
+ {
+ attributes.AddRange(serviceType.GetTypeInfo().GetCustomAttributes(true).OfType());
+ }
+
+ attributes.Sort((x, y) => x.Priority - y.Priority);
+
+ return attributes.ToArray();
}
///
@@ -531,11 +571,11 @@ namespace Emby.Server.Implementations.HttpServer
return;
}
- var handler = HttpHandlerFactory.GetHandler(httpReq, _logger);
+ var handler = GetServiceHandler(httpReq);
if (handler != null)
{
- await handler.ProcessRequestAsync(httpReq, httpRes, operationName).ConfigureAwait(false);
+ await handler.ProcessRequestAsync(this, httpReq, httpRes, Logger, operationName).ConfigureAwait(false);
}
else
{
@@ -565,6 +605,35 @@ namespace Emby.Server.Implementations.HttpServer
}
}
+ // Entry point for HttpListener
+ public ServiceHandler GetServiceHandler(IHttpRequest httpReq)
+ {
+ var pathInfo = httpReq.PathInfo;
+
+ var pathParts = pathInfo.TrimStart('/').Split('/');
+ if (pathParts.Length == 0)
+ {
+ _logger.Error("Path parts empty for PathInfo: {0}, Url: {1}", pathInfo, httpReq.RawUrl);
+ return null;
+ }
+
+ string contentType;
+ var restPath = ServiceHandler.FindMatchingRestPath(httpReq.HttpMethod, pathInfo, _logger, out contentType);
+
+ if (restPath != null)
+ {
+ return new ServiceHandler
+ {
+ RestPath = restPath,
+ ResponseContentType = contentType
+ };
+ }
+
+ _logger.Error("Could not find handler for {0}", pathInfo);
+ return null;
+ }
+
+
private void Write(IResponse response, string text)
{
var bOutput = Encoding.UTF8.GetBytes(text);
@@ -580,6 +649,7 @@ namespace Emby.Server.Implementations.HttpServer
httpRes.AddHeader("Location", url);
}
+ public ServiceController ServiceController { get; private set; }
///
/// Adds the rest handlers.
@@ -593,12 +663,20 @@ namespace Emby.Server.Implementations.HttpServer
_logger.Info("Calling ServiceStack AppHost.Init");
- base.Init();
+ ServiceController.Init(this);
+
+ var requestFilters = _appHost.GetExports().ToList();
+ foreach (var filter in requestFilters)
+ {
+ RequestFilters.Add(filter.Filter);
+ }
+
+ ResponseFilters.Add(new ResponseFilter(_logger).FilterResponse);
}
- public override RouteAttribute[] GetRouteAttributes(Type requestType)
+ public RouteAttribute[] GetRouteAttributes(Type requestType)
{
- var routes = base.GetRouteAttributes(requestType).ToList();
+ var routes = requestType.GetTypeInfo().GetCustomAttributes(true).ToList();
var clone = routes.ToList();
foreach (var route in clone)
@@ -628,54 +706,27 @@ namespace Emby.Server.Implementations.HttpServer
return routes.ToArray();
}
- public override object GetTaskResult(Task task, string requestName)
- {
- try
- {
- var taskObject = task as Task