diff --git a/Emby.Drawing/Emby.Drawing.csproj b/Emby.Drawing/Emby.Drawing.csproj index e9911a12d9..45ac97ecc4 100644 --- a/Emby.Drawing/Emby.Drawing.csproj +++ b/Emby.Drawing/Emby.Drawing.csproj @@ -33,11 +33,11 @@ False - ..\packages\CommonIO.1.0.0.5\lib\net45\CommonIO.dll + ..\packages\CommonIO.1.0.0.7\lib\net45\CommonIO.dll False - ..\packages\ImageMagickSharp.1.0.0.16\lib\net45\ImageMagickSharp.dll + ..\packages\ImageMagickSharp.1.0.0.17\lib\net45\ImageMagickSharp.dll ..\packages\Patterns.Logging.1.0.0.2\lib\portable-net45+sl4+wp71+win8+wpa81\Patterns.Logging.dll diff --git a/Emby.Drawing/ImageMagick/ImageMagickEncoder.cs b/Emby.Drawing/ImageMagick/ImageMagickEncoder.cs index 64ddf7e884..6858c6d520 100644 --- a/Emby.Drawing/ImageMagick/ImageMagickEncoder.cs +++ b/Emby.Drawing/ImageMagick/ImageMagickEncoder.cs @@ -72,11 +72,16 @@ namespace Emby.Drawing.ImageMagick private void LogVersion() { - _logger.Info("ImageMagick version: " + Wand.VersionString); + _logger.Info("ImageMagick version: " + GetVersion()); TestWebp(); Wand.SetMagickThreadCount(1); } + public static string GetVersion() + { + return Wand.VersionString; + } + private bool _webpAvailable = true; private void TestWebp() { @@ -148,7 +153,7 @@ namespace Emby.Drawing.ImageMagick DrawIndicator(originalImage, width, height, options); originalImage.CurrentImage.CompressionQuality = quality; - //originalImage.CurrentImage.StripImage(); + originalImage.CurrentImage.StripImage(); originalImage.SaveImage(outputPath); } @@ -165,7 +170,7 @@ namespace Emby.Drawing.ImageMagick DrawIndicator(wand, width, height, options); wand.CurrentImage.CompressionQuality = quality; - //wand.CurrentImage.StripImage(); + wand.CurrentImage.StripImage(); wand.SaveImage(outputPath); } @@ -176,15 +181,16 @@ namespace Emby.Drawing.ImageMagick private void ScaleImage(MagickWand wand, int width, int height) { - wand.CurrentImage.ResizeImage(width, height); - //if (_config.Configuration.EnableHighQualityImageScaling) - //{ - // wand.CurrentImage.ResizeImage(width, height); - //} - //else - //{ - // wand.CurrentImage.ScaleImage(width, height); - //} + var highQuality = false; + + if (highQuality) + { + wand.CurrentImage.ResizeImage(width, height); + } + else + { + wand.CurrentImage.ScaleImage(width, height); + } } /// diff --git a/Emby.Drawing/packages.config b/Emby.Drawing/packages.config index 0fcdc278e3..51731c4748 100644 --- a/Emby.Drawing/packages.config +++ b/Emby.Drawing/packages.config @@ -1,6 +1,6 @@  - - + + \ No newline at end of file diff --git a/MediaBrowser.Api/ItemLookupService.cs b/MediaBrowser.Api/ItemLookupService.cs index f453036d74..8e1abef14e 100644 --- a/MediaBrowser.Api/ItemLookupService.cs +++ b/MediaBrowser.Api/ItemLookupService.cs @@ -17,6 +17,7 @@ using System.Linq; using System.Threading; using System.Threading.Tasks; using CommonIO; +using MediaBrowser.Model.Serialization; namespace MediaBrowser.Api { @@ -112,13 +113,15 @@ namespace MediaBrowser.Api private readonly IServerApplicationPaths _appPaths; private readonly IFileSystem _fileSystem; private readonly ILibraryManager _libraryManager; + private readonly IJsonSerializer _json; - public ItemLookupService(IProviderManager providerManager, IServerApplicationPaths appPaths, IFileSystem fileSystem, ILibraryManager libraryManager) + public ItemLookupService(IProviderManager providerManager, IServerApplicationPaths appPaths, IFileSystem fileSystem, ILibraryManager libraryManager, IJsonSerializer json) { _providerManager = providerManager; _appPaths = appPaths; _fileSystem = fileSystem; _libraryManager = libraryManager; + _json = json; } public object Get(GetExternalIdInfos request) @@ -199,6 +202,7 @@ namespace MediaBrowser.Api // item.SetProviderId(key.Key, value); // } //} + Logger.Info("Setting provider id's to item {0}-{1}: {2}", item.Id, item.Name, _json.SerializeToString(request.ProviderIds)); item.ProviderIds = request.ProviderIds; var task = _providerManager.RefreshFullItem(item, new MetadataRefreshOptions(_fileSystem) diff --git a/MediaBrowser.Api/Library/LibraryService.cs b/MediaBrowser.Api/Library/LibraryService.cs index 319bc13fd2..b7066a36da 100644 --- a/MediaBrowser.Api/Library/LibraryService.cs +++ b/MediaBrowser.Api/Library/LibraryService.cs @@ -162,6 +162,14 @@ namespace MediaBrowser.Api.Library public string Id { get; set; } } + [Route("/Items", "DELETE", Summary = "Deletes an item from the library and file system")] + [Authenticated] + public class DeleteItems : IReturnVoid + { + [ApiMember(Name = "Ids", Description = "Ids", IsRequired = true, DataType = "string", ParameterType = "path", Verb = "DELETE")] + public string Ids { get; set; } + } + [Route("/Items/Counts", "GET")] [Authenticated] public class GetItemCounts : IReturn @@ -711,31 +719,53 @@ namespace MediaBrowser.Api.Library } } + /// + /// Deletes the specified request. + /// + /// The request. + public void Delete(DeleteItems request) + { + var ids = string.IsNullOrWhiteSpace(request.Ids) + ? new string[] { } + : request.Ids.Split(','); + + var tasks = ids.Select(i => + { + var item = _libraryManager.GetItemById(i); + var auth = _authContext.GetAuthorizationInfo(Request); + var user = _userManager.GetUserById(auth.UserId); + + if (!item.CanDelete(user)) + { + if (ids.Length > 1) + { + throw new SecurityException("Unauthorized access"); + } + + return Task.FromResult(true); + } + + if (item is ILiveTvRecording) + { + return _liveTv.DeleteRecording(i); + } + + return _libraryManager.DeleteItem(item); + }).ToArray(); + + Task.WaitAll(tasks); + } + /// /// Deletes the specified request. /// /// The request. public void Delete(DeleteItem request) { - var item = _libraryManager.GetItemById(request.Id); - var auth = _authContext.GetAuthorizationInfo(Request); - var user = _userManager.GetUserById(auth.UserId); - - if (!item.CanDelete(user)) + Delete(new DeleteItems { - throw new SecurityException("Unauthorized access"); - } - - if (item is ILiveTvRecording) - { - var task = _liveTv.DeleteRecording(request.Id); - Task.WaitAll(task); - } - else - { - var task = _libraryManager.DeleteItem(item); - Task.WaitAll(task); - } + Ids = request.Id + }); } /// diff --git a/MediaBrowser.Api/MediaBrowser.Api.csproj b/MediaBrowser.Api/MediaBrowser.Api.csproj index 7be644bc80..7e55446ae7 100644 --- a/MediaBrowser.Api/MediaBrowser.Api.csproj +++ b/MediaBrowser.Api/MediaBrowser.Api.csproj @@ -47,7 +47,10 @@ False - ..\packages\CommonIO.1.0.0.5\lib\net45\CommonIO.dll + ..\packages\CommonIO.1.0.0.7\lib\net45\CommonIO.dll + + + ..\packages\morelinq.1.4.0\lib\net35\MoreLinq.dll ..\packages\Patterns.Logging.1.0.0.2\lib\portable-net45+sl4+wp71+win8+wpa81\Patterns.Logging.dll @@ -63,9 +66,6 @@ ..\ThirdParty\ServiceStack.Text\ServiceStack.Text.dll - - ..\packages\morelinq.1.1.1\lib\net35\MoreLinq.dll - diff --git a/MediaBrowser.Api/PackageService.cs b/MediaBrowser.Api/PackageService.cs index 4f9efad50d..6d8378aaee 100644 --- a/MediaBrowser.Api/PackageService.cs +++ b/MediaBrowser.Api/PackageService.cs @@ -233,7 +233,7 @@ namespace MediaBrowser.Api throw new ResourceNotFoundException(string.Format("Package not found: {0}", request.Name)); } - Task.Run(() => _installationManager.InstallPackage(package, new Progress(), CancellationToken.None)); + Task.Run(() => _installationManager.InstallPackage(package, true, new Progress(), CancellationToken.None)); } /// diff --git a/MediaBrowser.Api/Playback/BaseStreamingService.cs b/MediaBrowser.Api/Playback/BaseStreamingService.cs index 4de29b3f2b..9e2e399d78 100644 --- a/MediaBrowser.Api/Playback/BaseStreamingService.cs +++ b/MediaBrowser.Api/Playback/BaseStreamingService.cs @@ -1562,6 +1562,13 @@ namespace MediaBrowser.Api.Playback RequestedUrl = url }; + //if ((Request.UserAgent ?? string.Empty).IndexOf("iphone", StringComparison.OrdinalIgnoreCase) != -1 || + // (Request.UserAgent ?? string.Empty).IndexOf("ipad", StringComparison.OrdinalIgnoreCase) != -1 || + // (Request.UserAgent ?? string.Empty).IndexOf("ipod", StringComparison.OrdinalIgnoreCase) != -1) + //{ + // state.SegmentLength = 6; + //} + if (!string.IsNullOrWhiteSpace(request.AudioCodec)) { state.SupportedAudioCodecs = request.AudioCodec.Split(',').Where(i => !string.IsNullOrWhiteSpace(i)).ToList(); diff --git a/MediaBrowser.Api/Playback/Hls/BaseHlsService.cs b/MediaBrowser.Api/Playback/Hls/BaseHlsService.cs index 60412159c6..766e8a003e 100644 --- a/MediaBrowser.Api/Playback/Hls/BaseHlsService.cs +++ b/MediaBrowser.Api/Playback/Hls/BaseHlsService.cs @@ -111,7 +111,8 @@ namespace MediaBrowser.Api.Playback.Hls throw; } - await WaitForMinimumSegmentCount(playlist, 3, cancellationTokenSource.Token).ConfigureAwait(false); + var waitForSegments = state.SegmentLength >= 10 ? 2 : 3; + await WaitForMinimumSegmentCount(playlist, waitForSegments, cancellationTokenSource.Token).ConfigureAwait(false); } } finally diff --git a/MediaBrowser.Api/SearchService.cs b/MediaBrowser.Api/SearchService.cs index 302b8d834c..602119d4f5 100644 --- a/MediaBrowser.Api/SearchService.cs +++ b/MediaBrowser.Api/SearchService.cs @@ -179,6 +179,7 @@ namespace MediaBrowser.Api if (primaryImageTag != null) { result.PrimaryImageTag = primaryImageTag; + result.PrimaryImageAspectRatio = _dtoService.GetPrimaryImageAspectRatio(item); } SetThumbImageInfo(result, item); diff --git a/MediaBrowser.Api/System/SystemService.cs b/MediaBrowser.Api/System/SystemService.cs index 3f2b3d66a3..2661c245fa 100644 --- a/MediaBrowser.Api/System/SystemService.cs +++ b/MediaBrowser.Api/System/SystemService.cs @@ -13,6 +13,7 @@ using System.IO; using System.Linq; using System.Threading.Tasks; using CommonIO; +using MediaBrowser.Model.Net; namespace MediaBrowser.Api.System { @@ -32,6 +33,12 @@ namespace MediaBrowser.Api.System } + [Route("/System/Ping", "POST")] + public class PingSystem : IReturnVoid + { + + } + /// /// Class RestartApplication /// @@ -59,7 +66,7 @@ namespace MediaBrowser.Api.System [Route("/System/Endpoint", "GET", Summary = "Gets information about the request endpoint")] [Authenticated] - public class GetEndpointInfo : IReturn + public class GetEndpointInfo : IReturn { public string Endpoint { get; set; } } @@ -104,6 +111,11 @@ namespace MediaBrowser.Api.System _security = security; } + public object Post(PingSystem request) + { + return _appHost.Name; + } + public object Get(GetServerLogs request) { List files; @@ -199,17 +211,11 @@ namespace MediaBrowser.Api.System public object Get(GetEndpointInfo request) { - return ToOptimizedResult(new EndpointInfo + return ToOptimizedResult(new EndPointInfo { IsLocal = Request.IsLocal, IsInNetwork = _network.IsInLocalNetwork(request.Endpoint ?? Request.RemoteIp) }); } } - - public class EndpointInfo - { - public bool IsLocal { get; set; } - public bool IsInNetwork { get; set; } - } } diff --git a/MediaBrowser.Api/packages.config b/MediaBrowser.Api/packages.config index d960123186..83890e6975 100644 --- a/MediaBrowser.Api/packages.config +++ b/MediaBrowser.Api/packages.config @@ -1,6 +1,6 @@  - - + + \ No newline at end of file diff --git a/MediaBrowser.Common.Implementations/BaseApplicationHost.cs b/MediaBrowser.Common.Implementations/BaseApplicationHost.cs index 6dc97100db..2a93efcdeb 100644 --- a/MediaBrowser.Common.Implementations/BaseApplicationHost.cs +++ b/MediaBrowser.Common.Implementations/BaseApplicationHost.cs @@ -133,7 +133,7 @@ namespace MediaBrowser.Common.Implementations /// Gets the HTTP client. /// /// The HTTP client. - protected IHttpClient HttpClient { get; private set; } + public IHttpClient HttpClient { get; private set; } /// /// Gets the network manager. /// diff --git a/MediaBrowser.Common.Implementations/HttpClientManager/HttpClientManager.cs b/MediaBrowser.Common.Implementations/HttpClientManager/HttpClientManager.cs index 054c5aaafb..c30cdf1a73 100644 --- a/MediaBrowser.Common.Implementations/HttpClientManager/HttpClientManager.cs +++ b/MediaBrowser.Common.Implementations/HttpClientManager/HttpClientManager.cs @@ -150,7 +150,7 @@ namespace MediaBrowser.Common.Implementations.HttpClientManager request.Method = method; request.Timeout = options.TimeoutMs; - + if (httpWebRequest != null) { if (!string.IsNullOrEmpty(options.Host)) diff --git a/MediaBrowser.Common.Implementations/MediaBrowser.Common.Implementations.csproj b/MediaBrowser.Common.Implementations/MediaBrowser.Common.Implementations.csproj index d857e58b68..cb3a284c11 100644 --- a/MediaBrowser.Common.Implementations/MediaBrowser.Common.Implementations.csproj +++ b/MediaBrowser.Common.Implementations/MediaBrowser.Common.Implementations.csproj @@ -49,11 +49,13 @@ False - ..\packages\CommonIO.1.0.0.5\lib\net45\CommonIO.dll + ..\packages\CommonIO.1.0.0.7\lib\net45\CommonIO.dll - - False - ..\packages\NLog.4.1.1\lib\net45\NLog.dll + + ..\packages\morelinq.1.4.0\lib\net35\MoreLinq.dll + + + ..\packages\NLog.4.2.3\lib\net45\NLog.dll ..\packages\Patterns.Logging.1.0.0.2\lib\portable-net45+sl4+wp71+win8+wpa81\Patterns.Logging.dll @@ -62,13 +64,14 @@ False ..\ThirdParty\SharpCompress\SharpCompress.dll - - False - ..\packages\SimpleInjector.3.0.5\lib\net45\SimpleInjector.dll + + ..\packages\SimpleInjector.3.1.2\lib\net45\SimpleInjector.dll + + @@ -105,6 +108,7 @@ + diff --git a/MediaBrowser.Common.Implementations/Networking/BaseNetworkManager.cs b/MediaBrowser.Common.Implementations/Networking/BaseNetworkManager.cs index c27dfd68d4..bc3dc360f7 100644 --- a/MediaBrowser.Common.Implementations/Networking/BaseNetworkManager.cs +++ b/MediaBrowser.Common.Implementations/Networking/BaseNetworkManager.cs @@ -7,6 +7,7 @@ using System.Net; using System.Net.NetworkInformation; using System.Net.Sockets; using System.Threading; +using MoreLinq; namespace MediaBrowser.Common.Implementations.Networking { @@ -31,14 +32,14 @@ namespace MediaBrowser.Common.Implementations.Networking } } - private volatile List _localIpAddresses; + private volatile List _localIpAddresses; private readonly object _localIpAddressSyncLock = new object(); /// /// Gets the machine's local ip address /// /// IPAddress. - public IEnumerable GetLocalIpAddresses() + public IEnumerable GetLocalIpAddresses() { if (_localIpAddresses == null) { @@ -58,25 +59,24 @@ namespace MediaBrowser.Common.Implementations.Networking return _localIpAddresses; } - private IEnumerable GetLocalIpAddressesInternal() + private IEnumerable GetLocalIpAddressesInternal() { var list = GetIPsDefault() - .Where(i => !IPAddress.IsLoopback(i)) - .Select(i => i.ToString()) - .Where(FilterIpAddress) .ToList(); - if (list.Count > 0) + if (list.Count == 0) { - return list; + list.AddRange(GetLocalIpAddressesFallback()); } - return GetLocalIpAddressesFallback().Where(FilterIpAddress); + return list.Where(FilterIpAddress).DistinctBy(i => i.ToString()); } - private bool FilterIpAddress(string address) + private bool FilterIpAddress(IPAddress address) { - if (address.StartsWith("169.", StringComparison.OrdinalIgnoreCase)) + var addressString = address.ToString (); + + if (addressString.StartsWith("169.", StringComparison.OrdinalIgnoreCase)) { return false; } @@ -84,8 +84,16 @@ namespace MediaBrowser.Common.Implementations.Networking return true; } - private bool IsInPrivateAddressSpace(string endpoint) + public bool IsInPrivateAddressSpace(string endpoint) { + if (string.Equals(endpoint, "::1", StringComparison.OrdinalIgnoreCase)) + { + return true; + } + + // Handle ipv4 mapped to ipv6 + endpoint = endpoint.Replace("::ffff:", string.Empty); + // Private address space: // http://en.wikipedia.org/wiki/Private_network @@ -96,9 +104,6 @@ namespace MediaBrowser.Common.Implementations.Networking return - // If url was requested with computer name, we may see this - endpoint.IndexOf("::", StringComparison.OrdinalIgnoreCase) != -1 || - endpoint.StartsWith("localhost", StringComparison.OrdinalIgnoreCase) || endpoint.StartsWith("127.", StringComparison.OrdinalIgnoreCase) || endpoint.StartsWith("10.", StringComparison.OrdinalIgnoreCase) || @@ -131,26 +136,41 @@ namespace MediaBrowser.Common.Implementations.Networking throw new ArgumentNullException("endpoint"); } - if (IsInPrivateAddressSpace(endpoint)) - { - return true; - } - - const int lengthMatch = 4; - - if (endpoint.Length >= lengthMatch) - { - var prefix = endpoint.Substring(0, lengthMatch); - - if (GetLocalIpAddresses() - .Any(i => i.StartsWith(prefix, StringComparison.OrdinalIgnoreCase))) - { - return true; - } - } - IPAddress address; - if (resolveHost && !IPAddress.TryParse(endpoint, out address)) + if (IPAddress.TryParse(endpoint, out address)) + { + var addressString = address.ToString(); + + int lengthMatch = 100; + if (address.AddressFamily == AddressFamily.InterNetwork) + { + lengthMatch = 4; + if (IsInPrivateAddressSpace(addressString)) + { + return true; + } + } + else if (address.AddressFamily == AddressFamily.InterNetworkV6) + { + lengthMatch = 10; + if (IsInPrivateAddressSpace(endpoint)) + { + return true; + } + } + + // Should be even be doing this with ipv6? + if (addressString.Length >= lengthMatch) + { + var prefix = addressString.Substring(0, lengthMatch); + + if (GetLocalIpAddresses().Any(i => i.ToString().StartsWith(prefix, StringComparison.OrdinalIgnoreCase))) + { + return true; + } + } + } + else if (resolveHost) { Uri uri; if (Uri.TryCreate(endpoint, UriKind.RelativeOrAbsolute, out uri)) @@ -188,33 +208,45 @@ namespace MediaBrowser.Common.Implementations.Networking return Dns.GetHostAddresses(hostName); } - private IEnumerable GetIPsDefault() - { - foreach (var adapter in NetworkInterface.GetAllNetworkInterfaces()) - { - var props = adapter.GetIPProperties(); - var gateways = from ga in props.GatewayAddresses - where !ga.Address.Equals(IPAddress.Any) - select true; + private List GetIPsDefault() + { + NetworkInterface[] interfaces; - if (!gateways.Any()) - { - continue; - } + try + { + interfaces = NetworkInterface.GetAllNetworkInterfaces(); + } + catch (Exception ex) + { + Logger.ErrorException("Error in GetAllNetworkInterfaces", ex); + return new List(); + } - foreach (var uni in props.UnicastAddresses) - { - var address = uni.Address; - if (address.AddressFamily != AddressFamily.InterNetwork) - { - continue; - } - yield return address; - } - } - } + return interfaces.SelectMany(network => { - private IEnumerable GetLocalIpAddressesFallback() + try + { + Logger.Debug("Querying interface: {0}. Type: {1}. Status: {2}", network.Name, network.NetworkInterfaceType, network.OperationalStatus); + + var properties = network.GetIPProperties(); + + return properties.UnicastAddresses + .Where(i => i.IsDnsEligible) + .Select(i => i.Address) + .Where(i => i.AddressFamily == AddressFamily.InterNetwork) + .ToList(); + } + catch (Exception ex) + { + Logger.ErrorException("Error querying network interface", ex); + return new List(); + } + + }).DistinctBy(i => i.ToString()) + .ToList(); + } + + private IEnumerable GetLocalIpAddressesFallback() { var host = Dns.GetHostEntry(Dns.GetHostName()); @@ -222,7 +254,6 @@ namespace MediaBrowser.Common.Implementations.Networking // It's not fool-proof so ultimately the consumer will have to examine them and decide return host.AddressList .Where(i => i.AddressFamily == AddressFamily.InterNetwork) - .Select(i => i.ToString()) .Reverse(); } diff --git a/MediaBrowser.Common.Implementations/Updates/GithubUpdater.cs b/MediaBrowser.Common.Implementations/Updates/GithubUpdater.cs new file mode 100644 index 0000000000..3604280729 --- /dev/null +++ b/MediaBrowser.Common.Implementations/Updates/GithubUpdater.cs @@ -0,0 +1,212 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Reflection; +using System.Text; +using System.Threading; +using System.Threading.Tasks; +using MediaBrowser.Common.Net; +using MediaBrowser.Model.Serialization; +using MediaBrowser.Model.Updates; + +namespace MediaBrowser.Common.Implementations.Updates +{ + public class GithubUpdater + { + private readonly IHttpClient _httpClient; + private readonly IJsonSerializer _jsonSerializer; + private TimeSpan _cacheLength; + + public GithubUpdater(IHttpClient httpClient, IJsonSerializer jsonSerializer, TimeSpan cacheLength) + { + _httpClient = httpClient; + _jsonSerializer = jsonSerializer; + _cacheLength = cacheLength; + } + + public async Task CheckForUpdateResult(string organzation, string repository, Version minVersion, PackageVersionClass updateLevel, string assetFilename, string packageName, string targetFilename, CancellationToken cancellationToken) + { + var url = string.Format("https://api.github.com/repos/{0}/{1}/releases", organzation, repository); + + var options = new HttpRequestOptions + { + Url = url, + EnableKeepAlive = false, + CancellationToken = cancellationToken, + UserAgent = "Emby/3.0" + + }; + + if (_cacheLength.Ticks > 0) + { + options.CacheMode = CacheMode.Unconditional; + options.CacheLength = _cacheLength; + } + + using (var stream = await _httpClient.Get(options).ConfigureAwait(false)) + { + var obj = _jsonSerializer.DeserializeFromStream(stream); + + return CheckForUpdateResult(obj, minVersion, updateLevel, assetFilename, packageName, targetFilename); + } + } + + private CheckForUpdateResult CheckForUpdateResult(RootObject[] obj, Version minVersion, PackageVersionClass updateLevel, string assetFilename, string packageName, string targetFilename) + { + if (updateLevel == PackageVersionClass.Release) + { + obj = obj.Where(i => !i.prerelease).ToArray(); + } + else if (updateLevel == PackageVersionClass.Beta) + { + obj = obj.Where(i => !i.prerelease || i.name.EndsWith("-beta", StringComparison.OrdinalIgnoreCase)).ToArray(); + } + else if (updateLevel == PackageVersionClass.Dev) + { + obj = obj.Where(i => !i.prerelease || i.name.EndsWith("-beta", StringComparison.OrdinalIgnoreCase) || i.name.EndsWith("-dev", StringComparison.OrdinalIgnoreCase)).ToArray(); + } + + var availableUpdate = obj + .Select(i => CheckForUpdateResult(i, minVersion, assetFilename, packageName, targetFilename)) + .Where(i => i != null) + .OrderByDescending(i => Version.Parse(i.AvailableVersion)) + .FirstOrDefault(); + + return availableUpdate ?? new CheckForUpdateResult + { + IsUpdateAvailable = false + }; + } + + private CheckForUpdateResult CheckForUpdateResult(RootObject obj, Version minVersion, string assetFilename, string packageName, string targetFilename) + { + Version version; + if (!Version.TryParse(obj.tag_name, out version)) + { + return null; + } + + if (version < minVersion) + { + return null; + } + + var asset = (obj.assets ?? new List()).FirstOrDefault(i => IsAsset(i, assetFilename)); + + if (asset == null) + { + return null; + } + + return new CheckForUpdateResult + { + AvailableVersion = version.ToString(), + IsUpdateAvailable = version > minVersion, + Package = new PackageVersionInfo + { + classification = obj.prerelease ? + (obj.name.EndsWith("-dev", StringComparison.OrdinalIgnoreCase) ? PackageVersionClass.Dev : PackageVersionClass.Beta) : + PackageVersionClass.Release, + name = packageName, + sourceUrl = asset.browser_download_url, + targetFilename = targetFilename, + versionStr = version.ToString(), + requiredVersionStr = "1.0.0", + description = obj.body + } + }; + } + + private bool IsAsset(Asset asset, string assetFilename) + { + var downloadFilename = Path.GetFileName(asset.browser_download_url) ?? string.Empty; + + if (downloadFilename.IndexOf(assetFilename, StringComparison.OrdinalIgnoreCase) != -1) + { + return true; + } + + return string.Equals(assetFilename, downloadFilename, StringComparison.OrdinalIgnoreCase); + } + + public class Uploader + { + public string login { get; set; } + public int id { get; set; } + public string avatar_url { get; set; } + public string gravatar_id { get; set; } + public string url { get; set; } + public string html_url { get; set; } + public string followers_url { get; set; } + public string following_url { get; set; } + public string gists_url { get; set; } + public string starred_url { get; set; } + public string subscriptions_url { get; set; } + public string organizations_url { get; set; } + public string repos_url { get; set; } + public string events_url { get; set; } + public string received_events_url { get; set; } + public string type { get; set; } + public bool site_admin { get; set; } + } + + public class Asset + { + public string url { get; set; } + public int id { get; set; } + public string name { get; set; } + public object label { get; set; } + public Uploader uploader { get; set; } + public string content_type { get; set; } + public string state { get; set; } + public int size { get; set; } + public int download_count { get; set; } + public string created_at { get; set; } + public string updated_at { get; set; } + public string browser_download_url { get; set; } + } + + public class Author + { + public string login { get; set; } + public int id { get; set; } + public string avatar_url { get; set; } + public string gravatar_id { get; set; } + public string url { get; set; } + public string html_url { get; set; } + public string followers_url { get; set; } + public string following_url { get; set; } + public string gists_url { get; set; } + public string starred_url { get; set; } + public string subscriptions_url { get; set; } + public string organizations_url { get; set; } + public string repos_url { get; set; } + public string events_url { get; set; } + public string received_events_url { get; set; } + public string type { get; set; } + public bool site_admin { get; set; } + } + + public class RootObject + { + public string url { get; set; } + public string assets_url { get; set; } + public string upload_url { get; set; } + public string html_url { get; set; } + public int id { get; set; } + public string tag_name { get; set; } + public string target_commitish { get; set; } + public string name { get; set; } + public bool draft { get; set; } + public Author author { get; set; } + public bool prerelease { get; set; } + public string created_at { get; set; } + public string published_at { get; set; } + public List assets { get; set; } + public string tarball_url { get; set; } + public string zipball_url { get; set; } + public string body { get; set; } + } + } +} diff --git a/MediaBrowser.Common.Implementations/Updates/InstallationManager.cs b/MediaBrowser.Common.Implementations/Updates/InstallationManager.cs index 6d68b968be..8e0df90050 100644 --- a/MediaBrowser.Common.Implementations/Updates/InstallationManager.cs +++ b/MediaBrowser.Common.Implementations/Updates/InstallationManager.cs @@ -437,11 +437,12 @@ namespace MediaBrowser.Common.Implementations.Updates /// Installs the package. /// /// The package. + /// if set to true [is plugin]. /// The progress. /// The cancellation token. /// Task. /// package - public async Task InstallPackage(PackageVersionInfo package, IProgress progress, CancellationToken cancellationToken) + public async Task InstallPackage(PackageVersionInfo package, bool isPlugin, IProgress progress, CancellationToken cancellationToken) { if (package == null) { @@ -494,7 +495,7 @@ namespace MediaBrowser.Common.Implementations.Updates try { - await InstallPackageInternal(package, innerProgress, linkedToken).ConfigureAwait(false); + await InstallPackageInternal(package, isPlugin, innerProgress, linkedToken).ConfigureAwait(false); lock (CurrentInstallations) { @@ -550,18 +551,17 @@ namespace MediaBrowser.Common.Implementations.Updates /// Installs the package internal. /// /// The package. + /// if set to true [is plugin]. /// The progress. /// The cancellation token. /// Task. - private async Task InstallPackageInternal(PackageVersionInfo package, IProgress progress, CancellationToken cancellationToken) + private async Task InstallPackageInternal(PackageVersionInfo package, bool isPlugin, IProgress progress, CancellationToken cancellationToken) { // Do the install await PerformPackageInstallation(progress, package, cancellationToken).ConfigureAwait(false); - var extension = Path.GetExtension(package.targetFilename) ?? ""; - // Do plugin-specific processing - if (!string.Equals(extension, ".zip", StringComparison.OrdinalIgnoreCase) && !string.Equals(extension, ".rar", StringComparison.OrdinalIgnoreCase) && !string.Equals(extension, ".7z", StringComparison.OrdinalIgnoreCase)) + if (isPlugin) { // Set last update time if we were installed before var plugin = _applicationHost.Plugins.FirstOrDefault(p => string.Equals(p.Id.ToString(), package.guid, StringComparison.OrdinalIgnoreCase)) diff --git a/MediaBrowser.Common.Implementations/packages.config b/MediaBrowser.Common.Implementations/packages.config index a0711a9c75..14f0f47197 100644 --- a/MediaBrowser.Common.Implementations/packages.config +++ b/MediaBrowser.Common.Implementations/packages.config @@ -1,7 +1,8 @@  - - + + + - + diff --git a/MediaBrowser.Common/Net/INetworkManager.cs b/MediaBrowser.Common/Net/INetworkManager.cs index 8fc947e8fe..de63ddd513 100644 --- a/MediaBrowser.Common/Net/INetworkManager.cs +++ b/MediaBrowser.Common/Net/INetworkManager.cs @@ -11,7 +11,7 @@ namespace MediaBrowser.Common.Net /// Gets the machine's local ip address /// /// IPAddress. - IEnumerable GetLocalIpAddresses(); + IEnumerable GetLocalIpAddresses(); /// /// Gets a random port number that is currently available @@ -25,6 +25,13 @@ namespace MediaBrowser.Common.Net /// [string] MAC Address string GetMacAddress(); + /// + /// Determines whether [is in private address space] [the specified endpoint]. + /// + /// The endpoint. + /// true if [is in private address space] [the specified endpoint]; otherwise, false. + bool IsInPrivateAddressSpace(string endpoint); + /// /// Gets the network shares. /// diff --git a/MediaBrowser.Common/Updates/IInstallationManager.cs b/MediaBrowser.Common/Updates/IInstallationManager.cs index 7d721da6f0..68853f05e7 100644 --- a/MediaBrowser.Common/Updates/IInstallationManager.cs +++ b/MediaBrowser.Common/Updates/IInstallationManager.cs @@ -105,11 +105,12 @@ namespace MediaBrowser.Common.Updates /// Installs the package. /// /// The package. + /// if set to true [is plugin]. /// The progress. /// The cancellation token. /// Task. /// package - Task InstallPackage(PackageVersionInfo package, IProgress progress, CancellationToken cancellationToken); + Task InstallPackage(PackageVersionInfo package, bool isPlugin, IProgress progress, CancellationToken cancellationToken); /// /// Uninstalls a plugin diff --git a/MediaBrowser.Controller/Dto/IDtoService.cs b/MediaBrowser.Controller/Dto/IDtoService.cs index e4ab291025..77a81d0c88 100644 --- a/MediaBrowser.Controller/Dto/IDtoService.cs +++ b/MediaBrowser.Controller/Dto/IDtoService.cs @@ -22,8 +22,14 @@ namespace MediaBrowser.Controller.Dto /// /// The dto. /// The item. - /// The fields. - void AttachPrimaryImageAspectRatio(IItemDto dto, IHasImages item, List fields); + void AttachPrimaryImageAspectRatio(IItemDto dto, IHasImages item); + + /// + /// Gets the primary image aspect ratio. + /// + /// The item. + /// System.Nullable<System.Double>. + double? GetPrimaryImageAspectRatio(IHasImages item); /// /// Gets the base item dto. diff --git a/MediaBrowser.Controller/IServerApplicationHost.cs b/MediaBrowser.Controller/IServerApplicationHost.cs index 1b842a5f62..fb843d1915 100644 --- a/MediaBrowser.Controller/IServerApplicationHost.cs +++ b/MediaBrowser.Controller/IServerApplicationHost.cs @@ -1,6 +1,8 @@ using MediaBrowser.Common; using MediaBrowser.Model.System; using System; +using System.Collections.Generic; +using System.Net; namespace MediaBrowser.Controller { @@ -63,7 +65,7 @@ namespace MediaBrowser.Controller /// Gets the local ip address. /// /// The local ip address. - string LocalIpAddress { get; } + List LocalIpAddresses { get; } /// /// Gets the local API URL. diff --git a/MediaBrowser.Controller/MediaBrowser.Controller.csproj b/MediaBrowser.Controller/MediaBrowser.Controller.csproj index bcf4de2a29..2227df3f03 100644 --- a/MediaBrowser.Controller/MediaBrowser.Controller.csproj +++ b/MediaBrowser.Controller/MediaBrowser.Controller.csproj @@ -46,11 +46,14 @@ False - ..\packages\CommonIO.1.0.0.5\lib\net45\CommonIO.dll + ..\packages\CommonIO.1.0.0.7\lib\net45\CommonIO.dll ..\packages\Interfaces.IO.1.0.0.5\lib\portable-net45+sl4+wp71+win8+wpa81\Interfaces.IO.dll + + ..\packages\morelinq.1.4.0\lib\net35\MoreLinq.dll + ..\packages\Patterns.Logging.1.0.0.2\lib\portable-net45+sl4+wp71+win8+wpa81\Patterns.Logging.dll @@ -65,9 +68,6 @@ ..\ThirdParty\ServiceStack\ServiceStack.Interfaces.dll - - ..\packages\morelinq.1.1.1\lib\net35\MoreLinq.dll - diff --git a/MediaBrowser.Controller/Net/IHttpServer.cs b/MediaBrowser.Controller/Net/IHttpServer.cs index 91da5fab20..97c5dd31b6 100644 --- a/MediaBrowser.Controller/Net/IHttpServer.cs +++ b/MediaBrowser.Controller/Net/IHttpServer.cs @@ -28,12 +28,6 @@ namespace MediaBrowser.Controller.Net /// the ssl certificate localtion on the file system. void StartServer(IEnumerable urlPrefixes, string certificatePath); - /// - /// Gets the local end points. - /// - /// The local end points. - IEnumerable LocalEndPoints { get; } - /// /// Stops this instance. /// diff --git a/MediaBrowser.Controller/packages.config b/MediaBrowser.Controller/packages.config index a0aacbc958..8439bee10b 100644 --- a/MediaBrowser.Controller/packages.config +++ b/MediaBrowser.Controller/packages.config @@ -1,7 +1,7 @@  - + - + \ No newline at end of file diff --git a/MediaBrowser.Dlna/Main/DlnaEntryPoint.cs b/MediaBrowser.Dlna/Main/DlnaEntryPoint.cs index 8c45757e76..d79ef9eafa 100644 --- a/MediaBrowser.Dlna/Main/DlnaEntryPoint.cs +++ b/MediaBrowser.Dlna/Main/DlnaEntryPoint.cs @@ -43,19 +43,19 @@ namespace MediaBrowser.Dlna.Main private readonly List _registeredServerIds = new List(); private bool _dlnaServerStarted; - public DlnaEntryPoint(IServerConfigurationManager config, - ILogManager logManager, - IServerApplicationHost appHost, - INetworkManager network, - ISessionManager sessionManager, - IHttpClient httpClient, - ILibraryManager libraryManager, - IUserManager userManager, - IDlnaManager dlnaManager, - IImageProcessor imageProcessor, - IUserDataManager userDataManager, - ILocalizationManager localization, - IMediaSourceManager mediaSourceManager, + public DlnaEntryPoint(IServerConfigurationManager config, + ILogManager logManager, + IServerApplicationHost appHost, + INetworkManager network, + ISessionManager sessionManager, + IHttpClient httpClient, + ILibraryManager libraryManager, + IUserManager userManager, + IDlnaManager dlnaManager, + IImageProcessor imageProcessor, + IUserDataManager userDataManager, + ILocalizationManager localization, + IMediaSourceManager mediaSourceManager, ISsdpHandler ssdpHandler, IDeviceDiscovery deviceDiscovery) { _config = config; @@ -148,13 +148,20 @@ namespace MediaBrowser.Dlna.Main private void RegisterServerEndpoints() { - foreach (var address in _network.GetLocalIpAddresses()) + foreach (var address in _appHost.LocalIpAddresses) { - var guid = address.GetMD5(); + //if (IPAddress.IsLoopback(address)) + //{ + // // Should we allow this? + // continue; + //} + + var addressString = address.ToString(); + var guid = addressString.GetMD5(); var descriptorURI = "/dlna/" + guid.ToString("N") + "/description.xml"; - var uri = new Uri(_appHost.GetLocalApiUrl(address) + descriptorURI); + var uri = new Uri(_appHost.GetLocalApiUrl(addressString) + descriptorURI); var services = new List { @@ -165,8 +172,8 @@ namespace MediaBrowser.Dlna.Main "urn:microsoft.com:service:X_MS_MediaReceiverRegistrar:1", "uuid:" + guid.ToString("N") }; - - _ssdpHandler.RegisterNotification(guid, uri, IPAddress.Parse(address), services); + + _ssdpHandler.RegisterNotification(guid, uri, address, services); _registeredServerIds.Add(guid.ToString("N")); } diff --git a/MediaBrowser.Dlna/MediaBrowser.Dlna.csproj b/MediaBrowser.Dlna/MediaBrowser.Dlna.csproj index b8ac60ef65..2d672ee873 100644 --- a/MediaBrowser.Dlna/MediaBrowser.Dlna.csproj +++ b/MediaBrowser.Dlna/MediaBrowser.Dlna.csproj @@ -42,7 +42,10 @@ False - ..\packages\CommonIO.1.0.0.5\lib\net45\CommonIO.dll + ..\packages\CommonIO.1.0.0.7\lib\net45\CommonIO.dll + + + ..\packages\morelinq.1.4.0\lib\net35\MoreLinq.dll ..\packages\Patterns.Logging.1.0.0.2\lib\portable-net45+sl4+wp71+win8+wpa81\Patterns.Logging.dll diff --git a/MediaBrowser.Dlna/Profiles/DefaultProfile.cs b/MediaBrowser.Dlna/Profiles/DefaultProfile.cs index 18a595d5b5..37ce0ce679 100644 --- a/MediaBrowser.Dlna/Profiles/DefaultProfile.cs +++ b/MediaBrowser.Dlna/Profiles/DefaultProfile.cs @@ -37,7 +37,6 @@ namespace MediaBrowser.Dlna.Profiles MusicSyncBitrate = 128000; EnableAlbumArtInDidl = false; - EnableDlnaProtocol = true; TranscodingProfiles = new[] { diff --git a/MediaBrowser.Dlna/Profiles/Xbox360Profile.cs b/MediaBrowser.Dlna/Profiles/Xbox360Profile.cs index 431807aedd..5a3e7b7c05 100644 --- a/MediaBrowser.Dlna/Profiles/Xbox360Profile.cs +++ b/MediaBrowser.Dlna/Profiles/Xbox360Profile.cs @@ -14,7 +14,7 @@ namespace MediaBrowser.Dlna.Profiles Name = "Xbox 360"; // Required according to above - ModelName = "Windows Media Connect"; + ModelName = "Windows Media Player Sharing"; ModelNumber = "12.0"; @@ -25,13 +25,11 @@ namespace MediaBrowser.Dlna.Profiles ManufacturerUrl = "http://www.microsoft.com"; XDlnaDoc = "DMS-1.50"; ModelDescription = "Emby : UPnP Media Server"; - ModelNumber = "001"; TimelineOffsetSeconds = 40; RequiresPlainFolders = true; RequiresPlainVideoItems = true; EnableMSMediaReceiverRegistrar = true; - EnableDlnaProtocol = false; Identification = new DeviceIdentification { diff --git a/MediaBrowser.Dlna/Profiles/XboxOneProfile.cs b/MediaBrowser.Dlna/Profiles/XboxOneProfile.cs index b78b5df0cb..e82f9b58cf 100644 --- a/MediaBrowser.Dlna/Profiles/XboxOneProfile.cs +++ b/MediaBrowser.Dlna/Profiles/XboxOneProfile.cs @@ -81,7 +81,7 @@ namespace MediaBrowser.Dlna.Profiles new DirectPlayProfile { Container = "mp4,mov,mkv", - VideoCodec = "h264,mpeg4", + VideoCodec = "h264,mpeg4,mpeg2video", AudioCodec = "aac,ac3", Type = DlnaProfileType.Video }, diff --git a/MediaBrowser.Dlna/Profiles/Xml/BubbleUPnp.xml b/MediaBrowser.Dlna/Profiles/Xml/BubbleUPnp.xml index ca98f950b6..29f7f7c759 100644 --- a/MediaBrowser.Dlna/Profiles/Xml/BubbleUPnp.xml +++ b/MediaBrowser.Dlna/Profiles/Xml/BubbleUPnp.xml @@ -34,7 +34,6 @@ false false false - true diff --git a/MediaBrowser.Dlna/Profiles/Xml/Default.xml b/MediaBrowser.Dlna/Profiles/Xml/Default.xml index 58c37a4238..6559e8971c 100644 --- a/MediaBrowser.Dlna/Profiles/Xml/Default.xml +++ b/MediaBrowser.Dlna/Profiles/Xml/Default.xml @@ -28,7 +28,6 @@ false false false - true diff --git a/MediaBrowser.Dlna/Profiles/Xml/Denon AVR.xml b/MediaBrowser.Dlna/Profiles/Xml/Denon AVR.xml index 86be2d18b3..da033f86e5 100644 --- a/MediaBrowser.Dlna/Profiles/Xml/Denon AVR.xml +++ b/MediaBrowser.Dlna/Profiles/Xml/Denon AVR.xml @@ -33,7 +33,6 @@ false false false - true diff --git a/MediaBrowser.Dlna/Profiles/Xml/DirecTV HD-DVR.xml b/MediaBrowser.Dlna/Profiles/Xml/DirecTV HD-DVR.xml index c553f9a069..d916f9984a 100644 --- a/MediaBrowser.Dlna/Profiles/Xml/DirecTV HD-DVR.xml +++ b/MediaBrowser.Dlna/Profiles/Xml/DirecTV HD-DVR.xml @@ -34,7 +34,6 @@ true false false - true diff --git a/MediaBrowser.Dlna/Profiles/Xml/Dish Hopper-Joey.xml b/MediaBrowser.Dlna/Profiles/Xml/Dish Hopper-Joey.xml index bb14ea309d..702f4ee6ce 100644 --- a/MediaBrowser.Dlna/Profiles/Xml/Dish Hopper-Joey.xml +++ b/MediaBrowser.Dlna/Profiles/Xml/Dish Hopper-Joey.xml @@ -35,7 +35,6 @@ false false false - true diff --git a/MediaBrowser.Dlna/Profiles/Xml/Kodi.xml b/MediaBrowser.Dlna/Profiles/Xml/Kodi.xml index 5d30d141e0..4a06c3122e 100644 --- a/MediaBrowser.Dlna/Profiles/Xml/Kodi.xml +++ b/MediaBrowser.Dlna/Profiles/Xml/Kodi.xml @@ -34,7 +34,6 @@ false false false - true diff --git a/MediaBrowser.Dlna/Profiles/Xml/LG Smart TV.xml b/MediaBrowser.Dlna/Profiles/Xml/LG Smart TV.xml index 62da6dbf47..e2b42a77e7 100644 --- a/MediaBrowser.Dlna/Profiles/Xml/LG Smart TV.xml +++ b/MediaBrowser.Dlna/Profiles/Xml/LG Smart TV.xml @@ -34,7 +34,6 @@ false false false - true diff --git a/MediaBrowser.Dlna/Profiles/Xml/Linksys DMA2100.xml b/MediaBrowser.Dlna/Profiles/Xml/Linksys DMA2100.xml index 9d83164d81..3d37a9c9eb 100644 --- a/MediaBrowser.Dlna/Profiles/Xml/Linksys DMA2100.xml +++ b/MediaBrowser.Dlna/Profiles/Xml/Linksys DMA2100.xml @@ -32,7 +32,6 @@ false false false - true diff --git a/MediaBrowser.Dlna/Profiles/Xml/MediaMonkey.xml b/MediaBrowser.Dlna/Profiles/Xml/MediaMonkey.xml index b66ebfe9ec..4249fd6ca7 100644 --- a/MediaBrowser.Dlna/Profiles/Xml/MediaMonkey.xml +++ b/MediaBrowser.Dlna/Profiles/Xml/MediaMonkey.xml @@ -34,7 +34,6 @@ false false false - true diff --git a/MediaBrowser.Dlna/Profiles/Xml/Panasonic Viera.xml b/MediaBrowser.Dlna/Profiles/Xml/Panasonic Viera.xml index 329c97fbd8..b468391ef4 100644 --- a/MediaBrowser.Dlna/Profiles/Xml/Panasonic Viera.xml +++ b/MediaBrowser.Dlna/Profiles/Xml/Panasonic Viera.xml @@ -35,7 +35,6 @@ false false false - true diff --git a/MediaBrowser.Dlna/Profiles/Xml/Popcorn Hour.xml b/MediaBrowser.Dlna/Profiles/Xml/Popcorn Hour.xml index a53e731cfb..ae9fc4de43 100644 --- a/MediaBrowser.Dlna/Profiles/Xml/Popcorn Hour.xml +++ b/MediaBrowser.Dlna/Profiles/Xml/Popcorn Hour.xml @@ -28,7 +28,6 @@ false false false - true diff --git a/MediaBrowser.Dlna/Profiles/Xml/Samsung Smart TV.xml b/MediaBrowser.Dlna/Profiles/Xml/Samsung Smart TV.xml index 642395ac85..2355fe7a44 100644 --- a/MediaBrowser.Dlna/Profiles/Xml/Samsung Smart TV.xml +++ b/MediaBrowser.Dlna/Profiles/Xml/Samsung Smart TV.xml @@ -34,7 +34,6 @@ false false false - true diff --git a/MediaBrowser.Dlna/Profiles/Xml/Sony Blu-ray Player 2013.xml b/MediaBrowser.Dlna/Profiles/Xml/Sony Blu-ray Player 2013.xml index afcce2b072..f273fcae0d 100644 --- a/MediaBrowser.Dlna/Profiles/Xml/Sony Blu-ray Player 2013.xml +++ b/MediaBrowser.Dlna/Profiles/Xml/Sony Blu-ray Player 2013.xml @@ -34,7 +34,6 @@ false false false - true diff --git a/MediaBrowser.Dlna/Profiles/Xml/Sony Blu-ray Player.xml b/MediaBrowser.Dlna/Profiles/Xml/Sony Blu-ray Player.xml index 8dc221251a..6132e19dc3 100644 --- a/MediaBrowser.Dlna/Profiles/Xml/Sony Blu-ray Player.xml +++ b/MediaBrowser.Dlna/Profiles/Xml/Sony Blu-ray Player.xml @@ -36,7 +36,6 @@ false false false - true diff --git a/MediaBrowser.Dlna/Profiles/Xml/Sony Bravia (2010).xml b/MediaBrowser.Dlna/Profiles/Xml/Sony Bravia (2010).xml index 69dae28065..fbd67262ad 100644 --- a/MediaBrowser.Dlna/Profiles/Xml/Sony Bravia (2010).xml +++ b/MediaBrowser.Dlna/Profiles/Xml/Sony Bravia (2010).xml @@ -36,7 +36,6 @@ false false false - true diff --git a/MediaBrowser.Dlna/Profiles/Xml/Sony Bravia (2011).xml b/MediaBrowser.Dlna/Profiles/Xml/Sony Bravia (2011).xml index 2292d634df..3f61b930b7 100644 --- a/MediaBrowser.Dlna/Profiles/Xml/Sony Bravia (2011).xml +++ b/MediaBrowser.Dlna/Profiles/Xml/Sony Bravia (2011).xml @@ -36,7 +36,6 @@ false false false - true diff --git a/MediaBrowser.Dlna/Profiles/Xml/Sony Bravia (2012).xml b/MediaBrowser.Dlna/Profiles/Xml/Sony Bravia (2012).xml index 095fcb28e3..0774d53f95 100644 --- a/MediaBrowser.Dlna/Profiles/Xml/Sony Bravia (2012).xml +++ b/MediaBrowser.Dlna/Profiles/Xml/Sony Bravia (2012).xml @@ -36,7 +36,6 @@ false false false - true diff --git a/MediaBrowser.Dlna/Profiles/Xml/Sony Bravia (2013).xml b/MediaBrowser.Dlna/Profiles/Xml/Sony Bravia (2013).xml index c700c4bfbc..c052cf85e3 100644 --- a/MediaBrowser.Dlna/Profiles/Xml/Sony Bravia (2013).xml +++ b/MediaBrowser.Dlna/Profiles/Xml/Sony Bravia (2013).xml @@ -36,7 +36,6 @@ false false false - true diff --git a/MediaBrowser.Dlna/Profiles/Xml/Sony Bravia (2014).xml b/MediaBrowser.Dlna/Profiles/Xml/Sony Bravia (2014).xml index 96fa2861dd..91cfc0db23 100644 --- a/MediaBrowser.Dlna/Profiles/Xml/Sony Bravia (2014).xml +++ b/MediaBrowser.Dlna/Profiles/Xml/Sony Bravia (2014).xml @@ -36,7 +36,6 @@ false false false - true diff --git a/MediaBrowser.Dlna/Profiles/Xml/Sony PlayStation 3.xml b/MediaBrowser.Dlna/Profiles/Xml/Sony PlayStation 3.xml index ce34dd5f29..b0825c8f63 100644 --- a/MediaBrowser.Dlna/Profiles/Xml/Sony PlayStation 3.xml +++ b/MediaBrowser.Dlna/Profiles/Xml/Sony PlayStation 3.xml @@ -36,7 +36,6 @@ false false false - true diff --git a/MediaBrowser.Dlna/Profiles/Xml/Sony PlayStation 4.xml b/MediaBrowser.Dlna/Profiles/Xml/Sony PlayStation 4.xml index 939c8a8139..670c8a6df1 100644 --- a/MediaBrowser.Dlna/Profiles/Xml/Sony PlayStation 4.xml +++ b/MediaBrowser.Dlna/Profiles/Xml/Sony PlayStation 4.xml @@ -36,7 +36,6 @@ false false false - true diff --git a/MediaBrowser.Dlna/Profiles/Xml/Vlc.xml b/MediaBrowser.Dlna/Profiles/Xml/Vlc.xml index 82b806f1a0..03d39350fe 100644 --- a/MediaBrowser.Dlna/Profiles/Xml/Vlc.xml +++ b/MediaBrowser.Dlna/Profiles/Xml/Vlc.xml @@ -34,7 +34,6 @@ false false false - true diff --git a/MediaBrowser.Dlna/Profiles/Xml/WDTV Live.xml b/MediaBrowser.Dlna/Profiles/Xml/WDTV Live.xml index df2a746d09..10b642bba4 100644 --- a/MediaBrowser.Dlna/Profiles/Xml/WDTV Live.xml +++ b/MediaBrowser.Dlna/Profiles/Xml/WDTV Live.xml @@ -35,7 +35,6 @@ false false true - true diff --git a/MediaBrowser.Dlna/Profiles/Xml/Xbox 360.xml b/MediaBrowser.Dlna/Profiles/Xml/Xbox 360.xml index bfe1fceea0..0724c2a83e 100644 --- a/MediaBrowser.Dlna/Profiles/Xml/Xbox 360.xml +++ b/MediaBrowser.Dlna/Profiles/Xml/Xbox 360.xml @@ -11,9 +11,9 @@ ${HostName}: 1 Microsoft Corporation http://www.microsoft.com - Windows Media Connect + Windows Media Player Sharing Emby : UPnP Media Server - 001 + 12.0 http://go.microsoft.com/fwlink/?LinkId=105926 false false @@ -35,7 +35,6 @@ true true false - false diff --git a/MediaBrowser.Dlna/Profiles/Xml/Xbox One.xml b/MediaBrowser.Dlna/Profiles/Xml/Xbox One.xml index bd315ac662..e4344f6ab6 100644 --- a/MediaBrowser.Dlna/Profiles/Xml/Xbox One.xml +++ b/MediaBrowser.Dlna/Profiles/Xml/Xbox One.xml @@ -35,13 +35,12 @@ false false false - true - + diff --git a/MediaBrowser.Dlna/Profiles/Xml/foobar2000.xml b/MediaBrowser.Dlna/Profiles/Xml/foobar2000.xml index a282af6556..8812118eab 100644 --- a/MediaBrowser.Dlna/Profiles/Xml/foobar2000.xml +++ b/MediaBrowser.Dlna/Profiles/Xml/foobar2000.xml @@ -34,7 +34,6 @@ false false false - true diff --git a/MediaBrowser.Dlna/Server/DescriptionXmlBuilder.cs b/MediaBrowser.Dlna/Server/DescriptionXmlBuilder.cs index 649612e1e4..386370596c 100644 --- a/MediaBrowser.Dlna/Server/DescriptionXmlBuilder.cs +++ b/MediaBrowser.Dlna/Server/DescriptionXmlBuilder.cs @@ -54,14 +54,11 @@ namespace MediaBrowser.Dlna.Server var attributes = _profile.XmlRootAttributes.ToList(); - if (_profile.EnableDlnaProtocol) + attributes.Insert(0, new XmlAttribute { - attributes.Insert(0, new XmlAttribute - { - Name = "xmlns:dlna", - Value = "urn:schemas-dlna-org:device-1-0" - }); - } + Name = "xmlns:dlna", + Value = "urn:schemas-dlna-org:device-1-0" + }); attributes.Insert(0, new XmlAttribute { Name = "xmlns", @@ -92,10 +89,7 @@ namespace MediaBrowser.Dlna.Server builder.Append(""); AppendDeviceProperties(builder); - if (_profile.EnableDlnaProtocol) - { - AppendIconList(builder); - } + AppendIconList(builder); AppendServiceList(builder); builder.Append(""); } @@ -104,13 +98,10 @@ namespace MediaBrowser.Dlna.Server { builder.Append("urn:schemas-upnp-org:device:MediaServer:1"); - if (_profile.EnableDlnaProtocol) - { - builder.Append("" + SecurityElement.Escape(_profile.XDlnaCap ?? string.Empty) + ""); + builder.Append("" + SecurityElement.Escape(_profile.XDlnaCap ?? string.Empty) + ""); - builder.Append("M-DMS-1.50"); - builder.Append("" + SecurityElement.Escape(_profile.XDlnaDoc ?? string.Empty) + ""); - } + builder.Append("M-DMS-1.50"); + builder.Append("" + SecurityElement.Escape(_profile.XDlnaDoc ?? string.Empty) + ""); builder.Append("" + SecurityElement.Escape(GetFriendlyName()) + ""); builder.Append("" + SecurityElement.Escape(_profile.Manufacturer ?? string.Empty) + ""); diff --git a/MediaBrowser.Dlna/Ssdp/DeviceDiscovery.cs b/MediaBrowser.Dlna/Ssdp/DeviceDiscovery.cs index c9b983baef..ed3698e437 100644 --- a/MediaBrowser.Dlna/Ssdp/DeviceDiscovery.cs +++ b/MediaBrowser.Dlna/Ssdp/DeviceDiscovery.cs @@ -11,6 +11,8 @@ using System.Net.NetworkInformation; using System.Net.Sockets; using System.Threading; using System.Threading.Tasks; +using MediaBrowser.Common.Net; +using MoreLinq; namespace MediaBrowser.Dlna.Ssdp { @@ -26,50 +28,39 @@ namespace MediaBrowser.Dlna.Ssdp public event EventHandler DeviceDiscovered; public event EventHandler DeviceLeft; + private readonly INetworkManager _networkManager; - public DeviceDiscovery(ILogger logger, IServerConfigurationManager config, IServerApplicationHost appHost) + public DeviceDiscovery(ILogger logger, IServerConfigurationManager config, IServerApplicationHost appHost, INetworkManager networkManager) { _tokenSource = new CancellationTokenSource(); _logger = logger; _config = config; _appHost = appHost; + _networkManager = networkManager; } + private List GetLocalIpAddresses() + { + return _networkManager.GetLocalIpAddresses().ToList(); + } + public void Start(SsdpHandler ssdpHandler) { _ssdpHandler = ssdpHandler; _ssdpHandler.MessageReceived += _ssdpHandler_MessageReceived; - foreach (var network in GetNetworkInterfaces()) - { - _logger.Debug("Found interface: {0}. Type: {1}. Status: {2}", network.Name, network.NetworkInterfaceType, network.OperationalStatus); - - if (!network.SupportsMulticast || OperationalStatus.Up != network.OperationalStatus || !network.GetIPProperties().MulticastAddresses.Any()) - continue; - - var properties = network.GetIPProperties(); - var ipV4 = properties.GetIPv4Properties(); - if (null == ipV4) - continue; - - var localIps = properties.UnicastAddresses - .Where(i => i.Address.AddressFamily == AddressFamily.InterNetwork) - .Select(i => i.Address) - .ToList(); - - foreach (var localIp in localIps) - { - try - { - CreateListener(localIp); - } - catch (Exception e) - { - _logger.ErrorException("Failed to Initilize Socket", e); - } - } - } + foreach (var localIp in GetLocalIpAddresses()) + { + try + { + CreateListener(localIp); + } + catch (Exception e) + { + _logger.ErrorException("Failed to Initilize Socket", e); + } + } } void _ssdpHandler_MessageReceived(object sender, SsdpMessageEventArgs e) @@ -89,8 +80,11 @@ namespace MediaBrowser.Dlna.Ssdp { if (e.LocalEndPoint == null) { - var ip = _appHost.LocalIpAddress; - e.LocalEndPoint = new IPEndPoint(IPAddress.Parse(ip), 0); + var ip = _appHost.LocalIpAddresses.FirstOrDefault(i => !IPAddress.IsLoopback(i)); + if (ip != null) + { + e.LocalEndPoint = new IPEndPoint(ip, 0); + } } if (e.LocalEndPoint != null) @@ -107,30 +101,18 @@ namespace MediaBrowser.Dlna.Ssdp } } - private IEnumerable GetNetworkInterfaces() - { - try - { - return NetworkInterface.GetAllNetworkInterfaces(); - } - catch (Exception ex) - { - _logger.ErrorException("Error in GetAllNetworkInterfaces", ex); - return new List(); - } - } private void CreateListener(IPAddress localIp) { Task.Factory.StartNew(async (o) => { try { - var endPoint = new IPEndPoint(localIp, 1900); + _logger.Info("Creating SSDP listener on {0}", localIp); + + var endPoint = new IPEndPoint(localIp, 1900); var socket = GetMulticastSocket(localIp, endPoint); - _logger.Info("Creating SSDP listener on {0}", localIp); - var receiveBuffer = new byte[64000]; CreateNotifier(localIp); diff --git a/MediaBrowser.Dlna/Ssdp/SsdpHandler.cs b/MediaBrowser.Dlna/Ssdp/SsdpHandler.cs index 5dd05fd64c..32c369a8ff 100644 --- a/MediaBrowser.Dlna/Ssdp/SsdpHandler.cs +++ b/MediaBrowser.Dlna/Ssdp/SsdpHandler.cs @@ -15,6 +15,7 @@ using System.Net.Sockets; using System.Text; using System.Threading; using System.Threading.Tasks; +using Microsoft.Win32; namespace MediaBrowser.Dlna.Ssdp { @@ -112,7 +113,9 @@ namespace MediaBrowser.Dlna.Ssdp { get { - return _devices.Values.SelectMany(i => i).ToList(); + var devices = _devices.Values.ToList(); + + return devices.SelectMany(i => i).ToList(); } } @@ -121,6 +124,15 @@ namespace MediaBrowser.Dlna.Ssdp RestartSocketListener(); ReloadAliveNotifier(); + SystemEvents.PowerModeChanged += SystemEvents_PowerModeChanged; + } + + void SystemEvents_PowerModeChanged(object sender, PowerModeChangedEventArgs e) + { + if (e.Mode == PowerModes.Resume) + { + NotifyAll(); + } } public void SendSearchMessage(EndPoint localIp) @@ -433,6 +445,7 @@ namespace MediaBrowser.Dlna.Ssdp public void Dispose() { _config.NamedConfigurationUpdated -= _config_ConfigurationUpdated; + SystemEvents.PowerModeChanged -= SystemEvents_PowerModeChanged; _isDisposed = true; while (_messageQueue.Count != 0) diff --git a/MediaBrowser.Dlna/packages.config b/MediaBrowser.Dlna/packages.config index fad6af08eb..83890e6975 100644 --- a/MediaBrowser.Dlna/packages.config +++ b/MediaBrowser.Dlna/packages.config @@ -1,5 +1,6 @@  - + + \ No newline at end of file diff --git a/MediaBrowser.LocalMetadata/MediaBrowser.LocalMetadata.csproj b/MediaBrowser.LocalMetadata/MediaBrowser.LocalMetadata.csproj index a74fe7e981..9a641776aa 100644 --- a/MediaBrowser.LocalMetadata/MediaBrowser.LocalMetadata.csproj +++ b/MediaBrowser.LocalMetadata/MediaBrowser.LocalMetadata.csproj @@ -33,7 +33,7 @@ False - ..\packages\CommonIO.1.0.0.5\lib\net45\CommonIO.dll + ..\packages\CommonIO.1.0.0.7\lib\net45\CommonIO.dll ..\packages\Patterns.Logging.1.0.0.2\lib\portable-net45+sl4+wp71+win8+wpa81\Patterns.Logging.dll diff --git a/MediaBrowser.LocalMetadata/packages.config b/MediaBrowser.LocalMetadata/packages.config index fad6af08eb..28556744da 100644 --- a/MediaBrowser.LocalMetadata/packages.config +++ b/MediaBrowser.LocalMetadata/packages.config @@ -1,5 +1,5 @@  - + \ No newline at end of file diff --git a/MediaBrowser.MediaEncoding/MediaBrowser.MediaEncoding.csproj b/MediaBrowser.MediaEncoding/MediaBrowser.MediaEncoding.csproj index df5ab46519..69f6186c7d 100644 --- a/MediaBrowser.MediaEncoding/MediaBrowser.MediaEncoding.csproj +++ b/MediaBrowser.MediaEncoding/MediaBrowser.MediaEncoding.csproj @@ -41,7 +41,7 @@ False - ..\packages\CommonIO.1.0.0.5\lib\net45\CommonIO.dll + ..\packages\CommonIO.1.0.0.7\lib\net45\CommonIO.dll ..\packages\MediaBrowser.BdInfo.1.0.0.10\lib\net35\DvdLib.dll diff --git a/MediaBrowser.MediaEncoding/packages.config b/MediaBrowser.MediaEncoding/packages.config index e8a1767e37..d6a4fc90f9 100644 --- a/MediaBrowser.MediaEncoding/packages.config +++ b/MediaBrowser.MediaEncoding/packages.config @@ -1,6 +1,6 @@  - + \ No newline at end of file diff --git a/MediaBrowser.Model/Dlna/DeviceProfile.cs b/MediaBrowser.Model/Dlna/DeviceProfile.cs index 5554c0623e..778db8fb54 100644 --- a/MediaBrowser.Model/Dlna/DeviceProfile.cs +++ b/MediaBrowser.Model/Dlna/DeviceProfile.cs @@ -78,7 +78,6 @@ namespace MediaBrowser.Model.Dlna public bool EnableMSMediaReceiverRegistrar { get; set; } public bool IgnoreTranscodeByteRangeRequests { get; set; } - public bool EnableDlnaProtocol { get; set; } public XmlAttribute[] XmlRootAttributes { get; set; } diff --git a/MediaBrowser.Model/Search/SearchHint.cs b/MediaBrowser.Model/Search/SearchHint.cs index d51c0325db..3a1d45cc43 100644 --- a/MediaBrowser.Model/Search/SearchHint.cs +++ b/MediaBrowser.Model/Search/SearchHint.cs @@ -144,5 +144,11 @@ namespace MediaBrowser.Model.Search /// /// The name of the channel. public string ChannelName { get; set; } + + /// + /// Gets or sets the primary image aspect ratio. + /// + /// The primary image aspect ratio. + public double? PrimaryImageAspectRatio { get; set; } } } diff --git a/MediaBrowser.Providers/Manager/ImageSaver.cs b/MediaBrowser.Providers/Manager/ImageSaver.cs index e8eece299a..4542c9c428 100644 --- a/MediaBrowser.Providers/Manager/ImageSaver.cs +++ b/MediaBrowser.Providers/Manager/ImageSaver.cs @@ -133,6 +133,7 @@ namespace MediaBrowser.Providers.Manager source = memoryStream; var currentImage = GetCurrentImage(item, type, index); + var savedPaths = new List(); using (source) { @@ -146,17 +147,17 @@ namespace MediaBrowser.Providers.Manager { retryPath = retryPaths[currentPathIndex]; } - await SaveImageToLocation(source, path, retryPath, cancellationToken).ConfigureAwait(false); - + var savedPath = await SaveImageToLocation(source, path, retryPath, cancellationToken).ConfigureAwait(false); + savedPaths.Add(savedPath); currentPathIndex++; } } // Set the path into the item - SetImagePath(item, type, imageIndex, paths[0]); + SetImagePath(item, type, imageIndex, savedPaths[0]); // Delete the current path - if (currentImage != null && currentImage.IsLocalFile && !paths.Contains(currentImage.Path, StringComparer.OrdinalIgnoreCase)) + if (currentImage != null && currentImage.IsLocalFile && !savedPaths.Contains(currentImage.Path, StringComparer.OrdinalIgnoreCase)) { var currentPath = currentImage.Path; @@ -184,11 +185,12 @@ namespace MediaBrowser.Providers.Manager } } - private async Task SaveImageToLocation(Stream source, string path, string retryPath, CancellationToken cancellationToken) + private async Task SaveImageToLocation(Stream source, string path, string retryPath, CancellationToken cancellationToken) { try { await SaveImageToLocation(source, path, cancellationToken).ConfigureAwait(false); + return path; } catch (UnauthorizedAccessException) { @@ -207,6 +209,7 @@ namespace MediaBrowser.Providers.Manager source.Position = 0; await SaveImageToLocation(source, retryPath, cancellationToken).ConfigureAwait(false); + return retryPath; } /// diff --git a/MediaBrowser.Providers/Manager/ProviderManager.cs b/MediaBrowser.Providers/Manager/ProviderManager.cs index 580e9c4ac3..090509ed33 100644 --- a/MediaBrowser.Providers/Manager/ProviderManager.cs +++ b/MediaBrowser.Providers/Manager/ProviderManager.cs @@ -795,22 +795,6 @@ namespace MediaBrowser.Providers.Manager } } - // This is a workaround duplicate check for movies, where intersecting provider ids are not always available - if (typeof(TItemType) == typeof(Movie) || typeof(TItemType) == typeof(Series)) - { - var titleYearString = string.Format("{0} ({1})", result.Name, result.ProductionYear); - - if (foundTitleYearStrings.Contains(titleYearString)) - { - bFound = true; - } - else - { - foundTitleYearStrings.Add(titleYearString); - } - - } - if (!bFound && resultList.Count < maxResults) { resultList.Add(result); diff --git a/MediaBrowser.Providers/MediaBrowser.Providers.csproj b/MediaBrowser.Providers/MediaBrowser.Providers.csproj index 731d30d845..8f6ef1d8fe 100644 --- a/MediaBrowser.Providers/MediaBrowser.Providers.csproj +++ b/MediaBrowser.Providers/MediaBrowser.Providers.csproj @@ -50,15 +50,14 @@ False - ..\packages\CommonIO.1.0.0.5\lib\net45\CommonIO.dll + ..\packages\CommonIO.1.0.0.7\lib\net45\CommonIO.dll False ..\packages\MediaBrowser.BdInfo.1.0.0.10\lib\net35\DvdLib.dll - - False - ..\packages\morelinq.1.1.1\lib\net35\MoreLinq.dll + + ..\packages\morelinq.1.4.0\lib\net35\MoreLinq.dll ..\packages\Patterns.Logging.1.0.0.2\lib\portable-net45+sl4+wp71+win8+wpa81\Patterns.Logging.dll diff --git a/MediaBrowser.Providers/Music/FanArtAlbumProvider.cs b/MediaBrowser.Providers/Music/FanArtAlbumProvider.cs index 3c6485fcc8..e72378d5da 100644 --- a/MediaBrowser.Providers/Music/FanArtAlbumProvider.cs +++ b/MediaBrowser.Providers/Music/FanArtAlbumProvider.cs @@ -68,7 +68,14 @@ namespace MediaBrowser.Providers.Music var list = new List(); - var artistMusicBrainzId = album.MusicArtist.GetProviderId(MetadataProviders.MusicBrainzArtist); + var musicArtist = album.MusicArtist; + + if (musicArtist == null) + { + return list; + } + + var artistMusicBrainzId = musicArtist.GetProviderId(MetadataProviders.MusicBrainzArtist); if (!string.IsNullOrEmpty(artistMusicBrainzId)) { diff --git a/MediaBrowser.Providers/Omdb/OmdbImageProvider.cs b/MediaBrowser.Providers/Omdb/OmdbImageProvider.cs index 3f25f0f930..a6f346d483 100644 --- a/MediaBrowser.Providers/Omdb/OmdbImageProvider.cs +++ b/MediaBrowser.Providers/Omdb/OmdbImageProvider.cs @@ -51,25 +51,15 @@ namespace MediaBrowser.Providers.Omdb return Task.FromResult>(list); } - public async Task GetImageResponse(string url, CancellationToken cancellationToken) + public Task GetImageResponse(string url, CancellationToken cancellationToken) { - var response = await _httpClient.GetResponse(new HttpRequestOptions + return _httpClient.GetResponse(new HttpRequestOptions { CancellationToken = cancellationToken, Url = url, ResourcePool = OmdbProvider.ResourcePool - }).ConfigureAwait(false); - - if (response.ContentLength == 11059) - { - throw new HttpException("File not found") - { - StatusCode = HttpStatusCode.NotFound - }; - } - - return response; + }); } public string Name diff --git a/MediaBrowser.Providers/Omdb/OmdbItemProvider.cs b/MediaBrowser.Providers/Omdb/OmdbItemProvider.cs index efcc76e694..30bd4bed77 100644 --- a/MediaBrowser.Providers/Omdb/OmdbItemProvider.cs +++ b/MediaBrowser.Providers/Omdb/OmdbItemProvider.cs @@ -57,7 +57,12 @@ namespace MediaBrowser.Providers.Omdb return GetSearchResults(searchInfo, "movie", cancellationToken); } - public async Task> GetSearchResults(ItemLookupInfo searchInfo, string type, CancellationToken cancellationToken) + public Task> GetSearchResults(ItemLookupInfo searchInfo, string type, CancellationToken cancellationToken) + { + return GetSearchResultsInternal(searchInfo, type, true, cancellationToken); + } + + private async Task> GetSearchResultsInternal(ItemLookupInfo searchInfo, string type, bool enableMultipleResults, CancellationToken cancellationToken) { bool isSearch = false; @@ -86,7 +91,14 @@ namespace MediaBrowser.Providers.Omdb } // &s means search and returns a list of results as opposed to t - url += "&s=" + WebUtility.UrlEncode(name); + if (enableMultipleResults) + { + url += "&s=" + WebUtility.UrlEncode(name); + } + else + { + url += "&t=" + WebUtility.UrlEncode(name); + } url += "&type=" + type; isSearch = true; } @@ -239,14 +251,14 @@ namespace MediaBrowser.Providers.Omdb private async Task GetMovieImdbId(ItemLookupInfo info, CancellationToken cancellationToken) { - var results = await GetSearchResults(info, "movie", cancellationToken).ConfigureAwait(false); + var results = await GetSearchResultsInternal(info, "movie", false, cancellationToken).ConfigureAwait(false); var first = results.FirstOrDefault(); return first == null ? null : first.GetProviderId(MetadataProviders.Imdb); } private async Task GetSeriesImdbId(SeriesInfo info, CancellationToken cancellationToken) { - var results = await GetSearchResults(info, cancellationToken).ConfigureAwait(false); + var results = await GetSearchResultsInternal(info, "series", false, cancellationToken).ConfigureAwait(false); var first = results.FirstOrDefault(); return first == null ? null : first.GetProviderId(MetadataProviders.Imdb); } diff --git a/MediaBrowser.Providers/Subtitles/OpenSubtitleDownloader.cs b/MediaBrowser.Providers/Subtitles/OpenSubtitleDownloader.cs index 74296db8aa..90b281e8ab 100644 --- a/MediaBrowser.Providers/Subtitles/OpenSubtitleDownloader.cs +++ b/MediaBrowser.Providers/Subtitles/OpenSubtitleDownloader.cs @@ -18,6 +18,7 @@ using System.IO; using System.Linq; using System.Threading; using System.Threading.Tasks; +using MediaBrowser.Model.Net; namespace MediaBrowser.Providers.Subtitles { @@ -30,15 +31,6 @@ namespace MediaBrowser.Providers.Subtitles private readonly IServerConfigurationManager _config; private readonly IEncryptionManager _encryption; - private Timer _dailyTimer; - - // This is limited to 200 per day - private int _dailyDownloadCount; - - // It's 200 but this will be in-exact so buffer a little - // And the user may restart the server - private const int MaxDownloadsPerDay = 150; - private readonly IJsonSerializer _json; public OpenSubtitleDownloader(ILogManager logManager, IHttpClient httpClient, IServerConfigurationManager config, IEncryptionManager encryption, IJsonSerializer json) @@ -51,9 +43,6 @@ namespace MediaBrowser.Providers.Subtitles _config.NamedConfigurationUpdating += _config_NamedConfigurationUpdating; - // Reset the count every 24 hours - _dailyTimer = new Timer(state => _dailyDownloadCount = 0, null, TimeSpan.FromHours(24), TimeSpan.FromHours(24)); - Utilities.HttpClient = httpClient; OpenSubtitles.SetUserAgent("mediabrowser.tv"); } @@ -123,6 +112,7 @@ namespace MediaBrowser.Providers.Subtitles return GetSubtitlesInternal(id, GetOptions(), cancellationToken); } + private DateTime _lastRateLimitException; private async Task GetSubtitlesInternal(string id, SubtitleOptions options, CancellationToken cancellationToken) @@ -132,12 +122,6 @@ namespace MediaBrowser.Providers.Subtitles throw new ArgumentNullException("id"); } - if (_dailyDownloadCount >= MaxDownloadsPerDay && - !options.IsOpenSubtitleVipAccount) - { - throw new InvalidOperationException("Open Subtitle's daily download limit has been exceeded. Please try again tomorrow."); - } - var idParts = id.Split(new[] { '-' }, 3); var format = idParts[0]; @@ -148,8 +132,19 @@ namespace MediaBrowser.Providers.Subtitles await Login(cancellationToken).ConfigureAwait(false); + if ((DateTime.UtcNow - _lastRateLimitException).TotalHours < 1) + { + throw new ApplicationException("OpenSubtitles rate limit reached"); + } + var resultDownLoad = await OpenSubtitles.DownloadSubtitlesAsync(downloadsList, cancellationToken).ConfigureAwait(false); + if ((resultDownLoad.Status ?? string.Empty).IndexOf("407", StringComparison.OrdinalIgnoreCase) != -1) + { + _lastRateLimitException = DateTime.UtcNow; + throw new ApplicationException("OpenSubtitles rate limit reached"); + } + if (!(resultDownLoad is MethodResponseSubtitleDownload)) { throw new ApplicationException("Invalid response type"); @@ -157,13 +152,15 @@ namespace MediaBrowser.Providers.Subtitles var results = ((MethodResponseSubtitleDownload)resultDownLoad).Results; + _lastRateLimitException = DateTime.MinValue; + if (results.Count == 0) { var msg = string.Format("Subtitle with Id {0} was not found. Name: {1}. Status: {2}. Message: {3}", ossId, resultDownLoad.Name ?? string.Empty, - resultDownLoad.Message ?? string.Empty, - resultDownLoad.Status ?? string.Empty); + resultDownLoad.Status ?? string.Empty, + resultDownLoad.Message ?? string.Empty); throw new ResourceNotFoundException(msg); } @@ -339,12 +336,6 @@ namespace MediaBrowser.Providers.Subtitles public void Dispose() { _config.NamedConfigurationUpdating -= _config_NamedConfigurationUpdating; - - if (_dailyTimer != null) - { - _dailyTimer.Dispose(); - _dailyTimer = null; - } } } } diff --git a/MediaBrowser.Providers/TV/TvdbEpisodeProvider.cs b/MediaBrowser.Providers/TV/TvdbEpisodeProvider.cs index 6b902ed8aa..d039207422 100644 --- a/MediaBrowser.Providers/TV/TvdbEpisodeProvider.cs +++ b/MediaBrowser.Providers/TV/TvdbEpisodeProvider.cs @@ -112,6 +112,8 @@ namespace MediaBrowser.Providers.TV if (TvdbSeriesProvider.IsValidSeries(searchInfo.SeriesProviderIds) && (searchInfo.IndexNumber.HasValue || searchInfo.PremiereDate.HasValue)) { + await TvdbSeriesProvider.Current.EnsureSeriesInfo(searchInfo.SeriesProviderIds, searchInfo.MetadataLanguage, cancellationToken).ConfigureAwait(false); + var seriesDataPath = TvdbSeriesProvider.GetSeriesDataPath(_config.ApplicationPaths, searchInfo.SeriesProviderIds); var searchNumbers = new EpisodeNumbers(); diff --git a/MediaBrowser.Providers/TV/TvdbSeriesProvider.cs b/MediaBrowser.Providers/TV/TvdbSeriesProvider.cs index 7250dbee4c..9452438cb1 100644 --- a/MediaBrowser.Providers/TV/TvdbSeriesProvider.cs +++ b/MediaBrowser.Providers/TV/TvdbSeriesProvider.cs @@ -222,6 +222,11 @@ namespace MediaBrowser.Providers.TV seriesId = await GetSeriesByRemoteId(seriesId, idType, preferredMetadataLanguage, cancellationToken).ConfigureAwait(false); } + if (string.IsNullOrWhiteSpace(seriesId)) + { + throw new ArgumentNullException("seriesId"); + } + var url = string.Format(SeriesGetZip, TVUtils.TvdbApiKey, seriesId, preferredMetadataLanguage); using (var zipStream = await _httpClient.Get(new HttpRequestOptions @@ -324,38 +329,48 @@ namespace MediaBrowser.Providers.TV return false; } + private SemaphoreSlim _ensureSemaphore = new SemaphoreSlim(1,1); internal async Task EnsureSeriesInfo(Dictionary seriesProviderIds, string preferredMetadataLanguage, CancellationToken cancellationToken) { - string seriesId; - if (seriesProviderIds.TryGetValue(MetadataProviders.Tvdb.ToString(), out seriesId)) - { - var seriesDataPath = GetSeriesDataPath(_config.ApplicationPaths, seriesProviderIds); + await _ensureSemaphore.WaitAsync(cancellationToken).ConfigureAwait(false); - // Only download if not already there - // The post-scan task will take care of updates so we don't need to re-download here - if (!IsCacheValid(seriesDataPath, preferredMetadataLanguage)) + try + { + string seriesId; + if (seriesProviderIds.TryGetValue(MetadataProviders.Tvdb.ToString(), out seriesId)) { - await DownloadSeriesZip(seriesId, MetadataProviders.Tvdb.ToString(), seriesDataPath, null, preferredMetadataLanguage, cancellationToken).ConfigureAwait(false); + var seriesDataPath = GetSeriesDataPath(_config.ApplicationPaths, seriesProviderIds); + + // Only download if not already there + // The post-scan task will take care of updates so we don't need to re-download here + if (!IsCacheValid(seriesDataPath, preferredMetadataLanguage)) + { + await DownloadSeriesZip(seriesId, MetadataProviders.Tvdb.ToString(), seriesDataPath, null, preferredMetadataLanguage, cancellationToken).ConfigureAwait(false); + } + + return seriesDataPath; } - return seriesDataPath; - } - - if (seriesProviderIds.TryGetValue(MetadataProviders.Imdb.ToString(), out seriesId)) - { - var seriesDataPath = GetSeriesDataPath(_config.ApplicationPaths, seriesProviderIds); - - // Only download if not already there - // The post-scan task will take care of updates so we don't need to re-download here - if (!IsCacheValid(seriesDataPath, preferredMetadataLanguage)) + if (seriesProviderIds.TryGetValue(MetadataProviders.Imdb.ToString(), out seriesId)) { - await DownloadSeriesZip(seriesId, MetadataProviders.Imdb.ToString(), seriesDataPath, null, preferredMetadataLanguage, cancellationToken).ConfigureAwait(false); + var seriesDataPath = GetSeriesDataPath(_config.ApplicationPaths, seriesProviderIds); + + // Only download if not already there + // The post-scan task will take care of updates so we don't need to re-download here + if (!IsCacheValid(seriesDataPath, preferredMetadataLanguage)) + { + await DownloadSeriesZip(seriesId, MetadataProviders.Imdb.ToString(), seriesDataPath, null, preferredMetadataLanguage, cancellationToken).ConfigureAwait(false); + } + + return seriesDataPath; } - return seriesDataPath; + return null; + } + finally + { + _ensureSemaphore.Release(); } - - return null; } private bool IsCacheValid(string seriesDataPath, string preferredMetadataLanguage) diff --git a/MediaBrowser.Providers/packages.config b/MediaBrowser.Providers/packages.config index 9ff08e4f4c..08f8ef3b05 100644 --- a/MediaBrowser.Providers/packages.config +++ b/MediaBrowser.Providers/packages.config @@ -1,8 +1,8 @@  - + - + \ No newline at end of file diff --git a/MediaBrowser.Server.Implementations/Dto/DtoService.cs b/MediaBrowser.Server.Implementations/Dto/DtoService.cs index bb7f818bad..b0071828e2 100644 --- a/MediaBrowser.Server.Implementations/Dto/DtoService.cs +++ b/MediaBrowser.Server.Implementations/Dto/DtoService.cs @@ -310,7 +310,7 @@ namespace MediaBrowser.Server.Implementations.Dto { try { - AttachPrimaryImageAspectRatio(dto, item, fields); + AttachPrimaryImageAspectRatio(dto, item); } catch (Exception ex) { @@ -1742,15 +1742,19 @@ namespace MediaBrowser.Server.Implementations.Dto /// /// The dto. /// The item. - /// The fields. /// Task. - public void AttachPrimaryImageAspectRatio(IItemDto dto, IHasImages item, List fields) + public void AttachPrimaryImageAspectRatio(IItemDto dto, IHasImages item) + { + dto.PrimaryImageAspectRatio = GetPrimaryImageAspectRatio(item); + } + + public double? GetPrimaryImageAspectRatio(IHasImages item) { var imageInfo = item.GetImageInfo(ImageType.Primary, 0); if (imageInfo == null || !imageInfo.IsLocalFile) { - return; + return null; } ImageSize size; @@ -1762,7 +1766,7 @@ namespace MediaBrowser.Server.Implementations.Dto catch (Exception ex) { //_logger.ErrorException("Failed to determine primary image aspect ratio for {0}", ex, path); - return; + return null; } var supportedEnhancers = _imageProcessor.GetSupportedEnhancers(item, ImageType.Primary).ToList(); @@ -1781,8 +1785,9 @@ namespace MediaBrowser.Server.Implementations.Dto if (size.Width > 0 && size.Height > 0) { - dto.PrimaryImageAspectRatio = size.Width / size.Height; + return size.Width / size.Height; } + return null; } } } diff --git a/MediaBrowser.Server.Implementations/FileOrganization/EpisodeFileOrganizer.cs b/MediaBrowser.Server.Implementations/FileOrganization/EpisodeFileOrganizer.cs index ef226a9341..26392f5a95 100644 --- a/MediaBrowser.Server.Implementations/FileOrganization/EpisodeFileOrganizer.cs +++ b/MediaBrowser.Server.Implementations/FileOrganization/EpisodeFileOrganizer.cs @@ -74,42 +74,52 @@ namespace MediaBrowser.Server.Implementations.FileOrganization if (!string.IsNullOrEmpty(seriesName)) { - var season = episodeInfo.SeasonNumber; + var seasonNumber = episodeInfo.SeasonNumber; - result.ExtractedSeasonNumber = season; + result.ExtractedSeasonNumber = seasonNumber; - if (season.HasValue) - { - // Passing in true will include a few extra regex's - var episode = episodeInfo.EpisodeNumber; + // Passing in true will include a few extra regex's + var episodeNumber = episodeInfo.EpisodeNumber; - result.ExtractedEpisodeNumber = episode; + result.ExtractedEpisodeNumber = episodeNumber; - if (episode.HasValue) - { - _logger.Debug("Extracted information from {0}. Series name {1}, Season {2}, Episode {3}", path, seriesName, season, episode); + var premiereDate = episodeInfo.IsByDate ? + new DateTime(episodeInfo.Year.Value, episodeInfo.Month.Value, episodeInfo.Day.Value) : + (DateTime?)null; - var endingEpisodeNumber = episodeInfo.EndingEpsiodeNumber; + if (episodeInfo.IsByDate || (seasonNumber.HasValue && episodeNumber.HasValue)) + { + if (episodeInfo.IsByDate) + { + _logger.Debug("Extracted information from {0}. Series name {1}, Date {2}", path, seriesName, premiereDate.Value); + } + else + { + _logger.Debug("Extracted information from {0}. Series name {1}, Season {2}, Episode {3}", path, seriesName, seasonNumber, episodeNumber); + } - result.ExtractedEndingEpisodeNumber = endingEpisodeNumber; + var endingEpisodeNumber = episodeInfo.EndingEpsiodeNumber; - await OrganizeEpisode(path, seriesName, season.Value, episode.Value, endingEpisodeNumber, options, overwriteExisting, result, cancellationToken).ConfigureAwait(false); - } - else - { - var msg = string.Format("Unable to determine episode number from {0}", path); - result.Status = FileSortingStatus.Failure; - result.StatusMessage = msg; - _logger.Warn(msg); - } - } - else - { - var msg = string.Format("Unable to determine season number from {0}", path); - result.Status = FileSortingStatus.Failure; - result.StatusMessage = msg; - _logger.Warn(msg); - } + result.ExtractedEndingEpisodeNumber = endingEpisodeNumber; + + await OrganizeEpisode(path, + seriesName, + seasonNumber, + episodeNumber, + endingEpisodeNumber, + premiereDate, + options, + overwriteExisting, + result, + cancellationToken).ConfigureAwait(false); + } + else + { + var msg = string.Format("Unable to determine episode number from {0}", path); + result.Status = FileSortingStatus.Failure; + result.StatusMessage = msg; + _logger.Warn(msg); + } } else { @@ -141,14 +151,32 @@ namespace MediaBrowser.Server.Implementations.FileOrganization var series = (Series)_libraryManager.GetItemById(new Guid(request.SeriesId)); - await OrganizeEpisode(result.OriginalPath, series, request.SeasonNumber, request.EpisodeNumber, request.EndingEpisodeNumber, options, true, result, cancellationToken).ConfigureAwait(false); + await OrganizeEpisode(result.OriginalPath, + series, + request.SeasonNumber, + request.EpisodeNumber, + request.EndingEpisodeNumber, + null, + options, + true, + result, + cancellationToken).ConfigureAwait(false); await _organizationService.SaveResult(result, CancellationToken.None).ConfigureAwait(false); return result; } - private Task OrganizeEpisode(string sourcePath, string seriesName, int seasonNumber, int episodeNumber, int? endingEpiosdeNumber, TvFileOrganizationOptions options, bool overwriteExisting, FileOrganizationResult result, CancellationToken cancellationToken) + private Task OrganizeEpisode(string sourcePath, + string seriesName, + int? seasonNumber, + int? episodeNumber, + int? endingEpiosdeNumber, + DateTime? premiereDate, + TvFileOrganizationOptions options, + bool overwriteExisting, + FileOrganizationResult result, + CancellationToken cancellationToken) { var series = GetMatchingSeries(seriesName, result); @@ -161,15 +189,33 @@ namespace MediaBrowser.Server.Implementations.FileOrganization return Task.FromResult(true); } - return OrganizeEpisode(sourcePath, series, seasonNumber, episodeNumber, endingEpiosdeNumber, options, overwriteExisting, result, cancellationToken); + return OrganizeEpisode(sourcePath, + series, + seasonNumber, + episodeNumber, + endingEpiosdeNumber, + premiereDate, + options, + overwriteExisting, + result, + cancellationToken); } - private async Task OrganizeEpisode(string sourcePath, Series series, int seasonNumber, int episodeNumber, int? endingEpiosdeNumber, TvFileOrganizationOptions options, bool overwriteExisting, FileOrganizationResult result, CancellationToken cancellationToken) + private async Task OrganizeEpisode(string sourcePath, + Series series, + int? seasonNumber, + int? episodeNumber, + int? endingEpiosdeNumber, + DateTime? premiereDate, + TvFileOrganizationOptions options, + bool overwriteExisting, + FileOrganizationResult result, + CancellationToken cancellationToken) { _logger.Info("Sorting file {0} into series {1}", sourcePath, series.Path); // Proceed to sort the file - var newPath = await GetNewPath(sourcePath, series, seasonNumber, episodeNumber, endingEpiosdeNumber, options, cancellationToken).ConfigureAwait(false); + var newPath = await GetNewPath(sourcePath, series, seasonNumber, episodeNumber, endingEpiosdeNumber, premiereDate, options, cancellationToken).ConfigureAwait(false); if (string.IsNullOrEmpty(newPath)) { @@ -278,8 +324,18 @@ namespace MediaBrowser.Server.Implementations.FileOrganization } } - private List GetOtherDuplicatePaths(string targetPath, Series series, int seasonNumber, int episodeNumber, int? endingEpisodeNumber) + private List GetOtherDuplicatePaths(string targetPath, + Series series, + int? seasonNumber, + int? episodeNumber, + int? endingEpisodeNumber) { + // TODO: Support date-naming? + if (!seasonNumber.HasValue || episodeNumber.HasValue) + { + return new List (); + } + var episodePaths = series.GetRecursiveChildren() .OfType() .Where(i => @@ -408,7 +464,14 @@ namespace MediaBrowser.Server.Implementations.FileOrganization /// The ending episode number. /// The options. /// System.String. - private async Task GetNewPath(string sourcePath, Series series, int seasonNumber, int episodeNumber, int? endingEpisodeNumber, TvFileOrganizationOptions options, CancellationToken cancellationToken) + private async Task GetNewPath(string sourcePath, + Series series, + int? seasonNumber, + int? episodeNumber, + int? endingEpisodeNumber, + DateTime? premiereDate, + TvFileOrganizationOptions options, + CancellationToken cancellationToken) { var episodeInfo = new EpisodeInfo { @@ -417,7 +480,8 @@ namespace MediaBrowser.Server.Implementations.FileOrganization MetadataCountryCode = series.GetPreferredMetadataCountryCode(), MetadataLanguage = series.GetPreferredMetadataLanguage(), ParentIndexNumber = seasonNumber, - SeriesProviderIds = series.ProviderIds + SeriesProviderIds = series.ProviderIds, + PremiereDate = premiereDate }; var searchResults = await _providerManager.GetRemoteSearchResults(new RemoteSearchQuery @@ -427,14 +491,24 @@ namespace MediaBrowser.Server.Implementations.FileOrganization }, cancellationToken).ConfigureAwait(false); var episode = searchResults.FirstOrDefault(); + + string episodeName = string.Empty; if (episode == null) { - _logger.Warn("No provider metadata found for {0} season {1} episode {2}", series.Name, seasonNumber, episodeNumber); - return null; + var msg = string.Format("No provider metadata found for {0} season {1} episode {2}", series.Name, seasonNumber, episodeNumber); + _logger.Warn(msg); + //throw new Exception(msg); } + else + { + episodeName = episode.Name; + } - var newPath = GetSeasonFolderPath(series, seasonNumber, options); + seasonNumber = seasonNumber ?? episode.ParentIndexNumber; + episodeNumber = episodeNumber ?? episode.IndexNumber; + + var newPath = GetSeasonFolderPath(series, seasonNumber.Value, options); // MAX_PATH - trailing charachter - drive component: 260 - 1 - 3 = 256 // Usually newPath would include the drive component, but use 256 to be sure @@ -449,7 +523,7 @@ namespace MediaBrowser.Server.Implementations.FileOrganization // Remove additional 4 chars to prevent PathTooLongException for downloaded subtitles (eg. filename.ext.eng.srt) maxFilenameLength -= 4; - var episodeFileName = GetEpisodeFileName(sourcePath, series.Name, seasonNumber, episodeNumber, endingEpisodeNumber, episode.Name, options, maxFilenameLength); + var episodeFileName = GetEpisodeFileName(sourcePath, series.Name, seasonNumber.Value, episodeNumber.Value, endingEpisodeNumber, episodeName, options, maxFilenameLength); if (string.IsNullOrEmpty(episodeFileName)) { @@ -505,7 +579,7 @@ namespace MediaBrowser.Server.Implementations.FileOrganization { seriesName = _fileSystem.GetValidFilename(seriesName).Trim(); - if (episodeTitle == null) + if (string.IsNullOrEmpty(episodeTitle)) { episodeTitle = string.Empty; } diff --git a/MediaBrowser.Server.Implementations/HttpServer/HttpListenerHost.cs b/MediaBrowser.Server.Implementations/HttpServer/HttpListenerHost.cs index 6ade9a8f6d..0283c1f7a5 100644 --- a/MediaBrowser.Server.Implementations/HttpServer/HttpListenerHost.cs +++ b/MediaBrowser.Server.Implementations/HttpServer/HttpListenerHost.cs @@ -19,6 +19,7 @@ using System.Linq; using System.Reflection; using System.Threading; using System.Threading.Tasks; +using MediaBrowser.Common.Net; using MediaBrowser.Common.Security; namespace MediaBrowser.Server.Implementations.HttpServer @@ -39,40 +40,20 @@ namespace MediaBrowser.Server.Implementations.HttpServer public event EventHandler WebSocketConnected; public event EventHandler WebSocketConnecting; - private readonly List _localEndpoints = new List(); - - private readonly ReaderWriterLockSlim _localEndpointLock = new ReaderWriterLockSlim(); - public string CertificatePath { get; private set; } private readonly IServerConfigurationManager _config; - - /// - /// Gets the local end points. - /// - /// The local end points. - public IEnumerable LocalEndPoints - { - get - { - _localEndpointLock.EnterReadLock(); - - var list = _localEndpoints.ToList(); - - _localEndpointLock.ExitReadLock(); - - return list; - } - } + private readonly INetworkManager _networkManager; public HttpListenerHost(IApplicationHost applicationHost, ILogManager logManager, IServerConfigurationManager config, string serviceName, - string defaultRedirectPath, params Assembly[] assembliesWithServices) + string defaultRedirectPath, INetworkManager networkManager, params Assembly[] assembliesWithServices) : base(serviceName, assembliesWithServices) { DefaultRedirectPath = defaultRedirectPath; + _networkManager = networkManager; _config = config; _logger = logManager.GetLogger("HttpServer"); @@ -175,26 +156,6 @@ namespace MediaBrowser.Server.Implementations.HttpServer private void OnRequestReceived(string localEndPoint) { - var ignore = localEndPoint.IndexOf("::", StringComparison.OrdinalIgnoreCase) != -1 || - - localEndPoint.StartsWith("127.", StringComparison.OrdinalIgnoreCase) || - localEndPoint.StartsWith("localhost", StringComparison.OrdinalIgnoreCase) || - localEndPoint.StartsWith("169.", StringComparison.OrdinalIgnoreCase); - - if (ignore) - { - return; - } - - if (_localEndpointLock.TryEnterWriteLock(100)) - { - var list = _localEndpoints.ToList(); - - list.Remove(localEndPoint); - list.Insert(0, localEndPoint); - - _localEndpointLock.ExitWriteLock(); - } } /// diff --git a/MediaBrowser.Server.Implementations/HttpServer/ResponseFilter.cs b/MediaBrowser.Server.Implementations/HttpServer/ResponseFilter.cs index 0da34efc67..4ef9d52774 100644 --- a/MediaBrowser.Server.Implementations/HttpServer/ResponseFilter.cs +++ b/MediaBrowser.Server.Implementations/HttpServer/ResponseFilter.cs @@ -58,7 +58,10 @@ namespace MediaBrowser.Server.Implementations.HttpServer if (hasOptions != null) { - hasOptions.Options["Server"] = "Mono-HTTPAPI/1.1"; + if (!hasOptions.Options.ContainsKey("Server")) + { + hasOptions.Options["Server"] = "Mono-HTTPAPI/1.1, UPnP/1.0 DLNADOC/1.50"; + } // Content length has to be explicitly set on on HttpListenerResponse or it won't be happy string contentLength; diff --git a/MediaBrowser.Server.Implementations/HttpServer/ServerFactory.cs b/MediaBrowser.Server.Implementations/HttpServer/ServerFactory.cs index 4d81ec157e..cc351f6b3e 100644 --- a/MediaBrowser.Server.Implementations/HttpServer/ServerFactory.cs +++ b/MediaBrowser.Server.Implementations/HttpServer/ServerFactory.cs @@ -1,4 +1,5 @@ using MediaBrowser.Common; +using MediaBrowser.Common.Net; using MediaBrowser.Controller.Configuration; using MediaBrowser.Controller.Net; using MediaBrowser.Model.Logging; @@ -17,18 +18,20 @@ namespace MediaBrowser.Server.Implementations.HttpServer /// The application host. /// The log manager. /// The configuration. + /// The _networkmanager. /// Name of the server. /// The default redirectpath. /// IHttpServer. public static IHttpServer CreateServer(IApplicationHost applicationHost, ILogManager logManager, IServerConfigurationManager config, + INetworkManager _networkmanager, string serverName, string defaultRedirectpath) { LogManager.LogFactory = new ServerLogFactory(logManager); - return new HttpListenerHost(applicationHost, logManager, config, serverName, defaultRedirectpath); + return new HttpListenerHost(applicationHost, logManager, config, serverName, defaultRedirectpath, _networkmanager); } } } diff --git a/MediaBrowser.Server.Implementations/HttpServer/SocketSharp/HttpUtility.cs b/MediaBrowser.Server.Implementations/HttpServer/SocketSharp/HttpUtility.cs new file mode 100644 index 0000000000..3ef48d13a0 --- /dev/null +++ b/MediaBrowser.Server.Implementations/HttpServer/SocketSharp/HttpUtility.cs @@ -0,0 +1,941 @@ +using System; +using System.Collections; +using System.Collections.Generic; +using System.Collections.Specialized; +using System.Text; + +namespace MediaBrowser.Server.Implementations.HttpServer.SocketSharp +{ + public static class MyHttpUtility + { + sealed class HttpQSCollection : NameValueCollection + { + public override string ToString() + { + int count = Count; + if (count == 0) + return ""; + StringBuilder sb = new StringBuilder(); + string[] keys = AllKeys; + for (int i = 0; i < count; i++) + { + sb.AppendFormat("{0}={1}&", keys[i], this[keys[i]]); + } + if (sb.Length > 0) + sb.Length--; + return sb.ToString(); + } + } + + // Must be sorted + static readonly long[] entities = new long[] { + (long)'A' << 56 | (long)'E' << 48 | (long)'l' << 40 | (long)'i' << 32 | (long)'g' << 24, + (long)'A' << 56 | (long)'a' << 48 | (long)'c' << 40 | (long)'u' << 32 | (long)'t' << 24 | (long)'e' << 16, + (long)'A' << 56 | (long)'c' << 48 | (long)'i' << 40 | (long)'r' << 32 | (long)'c' << 24, + (long)'A' << 56 | (long)'g' << 48 | (long)'r' << 40 | (long)'a' << 32 | (long)'v' << 24 | (long)'e' << 16, + (long)'A' << 56 | (long)'l' << 48 | (long)'p' << 40 | (long)'h' << 32 | (long)'a' << 24, + (long)'A' << 56 | (long)'r' << 48 | (long)'i' << 40 | (long)'n' << 32 | (long)'g' << 24, + (long)'A' << 56 | (long)'t' << 48 | (long)'i' << 40 | (long)'l' << 32 | (long)'d' << 24 | (long)'e' << 16, + (long)'A' << 56 | (long)'u' << 48 | (long)'m' << 40 | (long)'l' << 32, + (long)'B' << 56 | (long)'e' << 48 | (long)'t' << 40 | (long)'a' << 32, + (long)'C' << 56 | (long)'c' << 48 | (long)'e' << 40 | (long)'d' << 32 | (long)'i' << 24 | (long)'l' << 16, + (long)'C' << 56 | (long)'h' << 48 | (long)'i' << 40, + (long)'D' << 56 | (long)'a' << 48 | (long)'g' << 40 | (long)'g' << 32 | (long)'e' << 24 | (long)'r' << 16, + (long)'D' << 56 | (long)'e' << 48 | (long)'l' << 40 | (long)'t' << 32 | (long)'a' << 24, + (long)'E' << 56 | (long)'T' << 48 | (long)'H' << 40, + (long)'E' << 56 | (long)'a' << 48 | (long)'c' << 40 | (long)'u' << 32 | (long)'t' << 24 | (long)'e' << 16, + (long)'E' << 56 | (long)'c' << 48 | (long)'i' << 40 | (long)'r' << 32 | (long)'c' << 24, + (long)'E' << 56 | (long)'g' << 48 | (long)'r' << 40 | (long)'a' << 32 | (long)'v' << 24 | (long)'e' << 16, + (long)'E' << 56 | (long)'p' << 48 | (long)'s' << 40 | (long)'i' << 32 | (long)'l' << 24 | (long)'o' << 16 | (long)'n' << 8, + (long)'E' << 56 | (long)'t' << 48 | (long)'a' << 40, + (long)'E' << 56 | (long)'u' << 48 | (long)'m' << 40 | (long)'l' << 32, + (long)'G' << 56 | (long)'a' << 48 | (long)'m' << 40 | (long)'m' << 32 | (long)'a' << 24, + (long)'I' << 56 | (long)'a' << 48 | (long)'c' << 40 | (long)'u' << 32 | (long)'t' << 24 | (long)'e' << 16, + (long)'I' << 56 | (long)'c' << 48 | (long)'i' << 40 | (long)'r' << 32 | (long)'c' << 24, + (long)'I' << 56 | (long)'g' << 48 | (long)'r' << 40 | (long)'a' << 32 | (long)'v' << 24 | (long)'e' << 16, + (long)'I' << 56 | (long)'o' << 48 | (long)'t' << 40 | (long)'a' << 32, + (long)'I' << 56 | (long)'u' << 48 | (long)'m' << 40 | (long)'l' << 32, + (long)'K' << 56 | (long)'a' << 48 | (long)'p' << 40 | (long)'p' << 32 | (long)'a' << 24, + (long)'L' << 56 | (long)'a' << 48 | (long)'m' << 40 | (long)'b' << 32 | (long)'d' << 24 | (long)'a' << 16, + (long)'M' << 56 | (long)'u' << 48, + (long)'N' << 56 | (long)'t' << 48 | (long)'i' << 40 | (long)'l' << 32 | (long)'d' << 24 | (long)'e' << 16, + (long)'N' << 56 | (long)'u' << 48, + (long)'O' << 56 | (long)'E' << 48 | (long)'l' << 40 | (long)'i' << 32 | (long)'g' << 24, + (long)'O' << 56 | (long)'a' << 48 | (long)'c' << 40 | (long)'u' << 32 | (long)'t' << 24 | (long)'e' << 16, + (long)'O' << 56 | (long)'c' << 48 | (long)'i' << 40 | (long)'r' << 32 | (long)'c' << 24, + (long)'O' << 56 | (long)'g' << 48 | (long)'r' << 40 | (long)'a' << 32 | (long)'v' << 24 | (long)'e' << 16, + (long)'O' << 56 | (long)'m' << 48 | (long)'e' << 40 | (long)'g' << 32 | (long)'a' << 24, + (long)'O' << 56 | (long)'m' << 48 | (long)'i' << 40 | (long)'c' << 32 | (long)'r' << 24 | (long)'o' << 16 | (long)'n' << 8, + (long)'O' << 56 | (long)'s' << 48 | (long)'l' << 40 | (long)'a' << 32 | (long)'s' << 24 | (long)'h' << 16, + (long)'O' << 56 | (long)'t' << 48 | (long)'i' << 40 | (long)'l' << 32 | (long)'d' << 24 | (long)'e' << 16, + (long)'O' << 56 | (long)'u' << 48 | (long)'m' << 40 | (long)'l' << 32, + (long)'P' << 56 | (long)'h' << 48 | (long)'i' << 40, + (long)'P' << 56 | (long)'i' << 48, + (long)'P' << 56 | (long)'r' << 48 | (long)'i' << 40 | (long)'m' << 32 | (long)'e' << 24, + (long)'P' << 56 | (long)'s' << 48 | (long)'i' << 40, + (long)'R' << 56 | (long)'h' << 48 | (long)'o' << 40, + (long)'S' << 56 | (long)'c' << 48 | (long)'a' << 40 | (long)'r' << 32 | (long)'o' << 24 | (long)'n' << 16, + (long)'S' << 56 | (long)'i' << 48 | (long)'g' << 40 | (long)'m' << 32 | (long)'a' << 24, + (long)'T' << 56 | (long)'H' << 48 | (long)'O' << 40 | (long)'R' << 32 | (long)'N' << 24, + (long)'T' << 56 | (long)'a' << 48 | (long)'u' << 40, + (long)'T' << 56 | (long)'h' << 48 | (long)'e' << 40 | (long)'t' << 32 | (long)'a' << 24, + (long)'U' << 56 | (long)'a' << 48 | (long)'c' << 40 | (long)'u' << 32 | (long)'t' << 24 | (long)'e' << 16, + (long)'U' << 56 | (long)'c' << 48 | (long)'i' << 40 | (long)'r' << 32 | (long)'c' << 24, + (long)'U' << 56 | (long)'g' << 48 | (long)'r' << 40 | (long)'a' << 32 | (long)'v' << 24 | (long)'e' << 16, + (long)'U' << 56 | (long)'p' << 48 | (long)'s' << 40 | (long)'i' << 32 | (long)'l' << 24 | (long)'o' << 16 | (long)'n' << 8, + (long)'U' << 56 | (long)'u' << 48 | (long)'m' << 40 | (long)'l' << 32, + (long)'X' << 56 | (long)'i' << 48, + (long)'Y' << 56 | (long)'a' << 48 | (long)'c' << 40 | (long)'u' << 32 | (long)'t' << 24 | (long)'e' << 16, + (long)'Y' << 56 | (long)'u' << 48 | (long)'m' << 40 | (long)'l' << 32, + (long)'Z' << 56 | (long)'e' << 48 | (long)'t' << 40 | (long)'a' << 32, + (long)'a' << 56 | (long)'a' << 48 | (long)'c' << 40 | (long)'u' << 32 | (long)'t' << 24 | (long)'e' << 16, + (long)'a' << 56 | (long)'c' << 48 | (long)'i' << 40 | (long)'r' << 32 | (long)'c' << 24, + (long)'a' << 56 | (long)'c' << 48 | (long)'u' << 40 | (long)'t' << 32 | (long)'e' << 24, + (long)'a' << 56 | (long)'e' << 48 | (long)'l' << 40 | (long)'i' << 32 | (long)'g' << 24, + (long)'a' << 56 | (long)'g' << 48 | (long)'r' << 40 | (long)'a' << 32 | (long)'v' << 24 | (long)'e' << 16, + (long)'a' << 56 | (long)'l' << 48 | (long)'e' << 40 | (long)'f' << 32 | (long)'s' << 24 | (long)'y' << 16 | (long)'m' << 8, + (long)'a' << 56 | (long)'l' << 48 | (long)'p' << 40 | (long)'h' << 32 | (long)'a' << 24, + (long)'a' << 56 | (long)'m' << 48 | (long)'p' << 40, + (long)'a' << 56 | (long)'n' << 48 | (long)'d' << 40, + (long)'a' << 56 | (long)'n' << 48 | (long)'g' << 40, + (long)'a' << 56 | (long)'p' << 48 | (long)'o' << 40 | (long)'s' << 32, + (long)'a' << 56 | (long)'r' << 48 | (long)'i' << 40 | (long)'n' << 32 | (long)'g' << 24, + (long)'a' << 56 | (long)'s' << 48 | (long)'y' << 40 | (long)'m' << 32 | (long)'p' << 24, + (long)'a' << 56 | (long)'t' << 48 | (long)'i' << 40 | (long)'l' << 32 | (long)'d' << 24 | (long)'e' << 16, + (long)'a' << 56 | (long)'u' << 48 | (long)'m' << 40 | (long)'l' << 32, + (long)'b' << 56 | (long)'d' << 48 | (long)'q' << 40 | (long)'u' << 32 | (long)'o' << 24, + (long)'b' << 56 | (long)'e' << 48 | (long)'t' << 40 | (long)'a' << 32, + (long)'b' << 56 | (long)'r' << 48 | (long)'v' << 40 | (long)'b' << 32 | (long)'a' << 24 | (long)'r' << 16, + (long)'b' << 56 | (long)'u' << 48 | (long)'l' << 40 | (long)'l' << 32, + (long)'c' << 56 | (long)'a' << 48 | (long)'p' << 40, + (long)'c' << 56 | (long)'c' << 48 | (long)'e' << 40 | (long)'d' << 32 | (long)'i' << 24 | (long)'l' << 16, + (long)'c' << 56 | (long)'e' << 48 | (long)'d' << 40 | (long)'i' << 32 | (long)'l' << 24, + (long)'c' << 56 | (long)'e' << 48 | (long)'n' << 40 | (long)'t' << 32, + (long)'c' << 56 | (long)'h' << 48 | (long)'i' << 40, + (long)'c' << 56 | (long)'i' << 48 | (long)'r' << 40 | (long)'c' << 32, + (long)'c' << 56 | (long)'l' << 48 | (long)'u' << 40 | (long)'b' << 32 | (long)'s' << 24, + (long)'c' << 56 | (long)'o' << 48 | (long)'n' << 40 | (long)'g' << 32, + (long)'c' << 56 | (long)'o' << 48 | (long)'p' << 40 | (long)'y' << 32, + (long)'c' << 56 | (long)'r' << 48 | (long)'a' << 40 | (long)'r' << 32 | (long)'r' << 24, + (long)'c' << 56 | (long)'u' << 48 | (long)'p' << 40, + (long)'c' << 56 | (long)'u' << 48 | (long)'r' << 40 | (long)'r' << 32 | (long)'e' << 24 | (long)'n' << 16, + (long)'d' << 56 | (long)'A' << 48 | (long)'r' << 40 | (long)'r' << 32, + (long)'d' << 56 | (long)'a' << 48 | (long)'g' << 40 | (long)'g' << 32 | (long)'e' << 24 | (long)'r' << 16, + (long)'d' << 56 | (long)'a' << 48 | (long)'r' << 40 | (long)'r' << 32, + (long)'d' << 56 | (long)'e' << 48 | (long)'g' << 40, + (long)'d' << 56 | (long)'e' << 48 | (long)'l' << 40 | (long)'t' << 32 | (long)'a' << 24, + (long)'d' << 56 | (long)'i' << 48 | (long)'a' << 40 | (long)'m' << 32 | (long)'s' << 24, + (long)'d' << 56 | (long)'i' << 48 | (long)'v' << 40 | (long)'i' << 32 | (long)'d' << 24 | (long)'e' << 16, + (long)'e' << 56 | (long)'a' << 48 | (long)'c' << 40 | (long)'u' << 32 | (long)'t' << 24 | (long)'e' << 16, + (long)'e' << 56 | (long)'c' << 48 | (long)'i' << 40 | (long)'r' << 32 | (long)'c' << 24, + (long)'e' << 56 | (long)'g' << 48 | (long)'r' << 40 | (long)'a' << 32 | (long)'v' << 24 | (long)'e' << 16, + (long)'e' << 56 | (long)'m' << 48 | (long)'p' << 40 | (long)'t' << 32 | (long)'y' << 24, + (long)'e' << 56 | (long)'m' << 48 | (long)'s' << 40 | (long)'p' << 32, + (long)'e' << 56 | (long)'n' << 48 | (long)'s' << 40 | (long)'p' << 32, + (long)'e' << 56 | (long)'p' << 48 | (long)'s' << 40 | (long)'i' << 32 | (long)'l' << 24 | (long)'o' << 16 | (long)'n' << 8, + (long)'e' << 56 | (long)'q' << 48 | (long)'u' << 40 | (long)'i' << 32 | (long)'v' << 24, + (long)'e' << 56 | (long)'t' << 48 | (long)'a' << 40, + (long)'e' << 56 | (long)'t' << 48 | (long)'h' << 40, + (long)'e' << 56 | (long)'u' << 48 | (long)'m' << 40 | (long)'l' << 32, + (long)'e' << 56 | (long)'u' << 48 | (long)'r' << 40 | (long)'o' << 32, + (long)'e' << 56 | (long)'x' << 48 | (long)'i' << 40 | (long)'s' << 32 | (long)'t' << 24, + (long)'f' << 56 | (long)'n' << 48 | (long)'o' << 40 | (long)'f' << 32, + (long)'f' << 56 | (long)'o' << 48 | (long)'r' << 40 | (long)'a' << 32 | (long)'l' << 24 | (long)'l' << 16, + (long)'f' << 56 | (long)'r' << 48 | (long)'a' << 40 | (long)'c' << 32 | (long)'1' << 24 | (long)'2' << 16, + (long)'f' << 56 | (long)'r' << 48 | (long)'a' << 40 | (long)'c' << 32 | (long)'1' << 24 | (long)'4' << 16, + (long)'f' << 56 | (long)'r' << 48 | (long)'a' << 40 | (long)'c' << 32 | (long)'3' << 24 | (long)'4' << 16, + (long)'f' << 56 | (long)'r' << 48 | (long)'a' << 40 | (long)'s' << 32 | (long)'l' << 24, + (long)'g' << 56 | (long)'a' << 48 | (long)'m' << 40 | (long)'m' << 32 | (long)'a' << 24, + (long)'g' << 56 | (long)'e' << 48, + (long)'g' << 56 | (long)'t' << 48, + (long)'h' << 56 | (long)'A' << 48 | (long)'r' << 40 | (long)'r' << 32, + (long)'h' << 56 | (long)'a' << 48 | (long)'r' << 40 | (long)'r' << 32, + (long)'h' << 56 | (long)'e' << 48 | (long)'a' << 40 | (long)'r' << 32 | (long)'t' << 24 | (long)'s' << 16, + (long)'h' << 56 | (long)'e' << 48 | (long)'l' << 40 | (long)'l' << 32 | (long)'i' << 24 | (long)'p' << 16, + (long)'i' << 56 | (long)'a' << 48 | (long)'c' << 40 | (long)'u' << 32 | (long)'t' << 24 | (long)'e' << 16, + (long)'i' << 56 | (long)'c' << 48 | (long)'i' << 40 | (long)'r' << 32 | (long)'c' << 24, + (long)'i' << 56 | (long)'e' << 48 | (long)'x' << 40 | (long)'c' << 32 | (long)'l' << 24, + (long)'i' << 56 | (long)'g' << 48 | (long)'r' << 40 | (long)'a' << 32 | (long)'v' << 24 | (long)'e' << 16, + (long)'i' << 56 | (long)'m' << 48 | (long)'a' << 40 | (long)'g' << 32 | (long)'e' << 24, + (long)'i' << 56 | (long)'n' << 48 | (long)'f' << 40 | (long)'i' << 32 | (long)'n' << 24, + (long)'i' << 56 | (long)'n' << 48 | (long)'t' << 40, + (long)'i' << 56 | (long)'o' << 48 | (long)'t' << 40 | (long)'a' << 32, + (long)'i' << 56 | (long)'q' << 48 | (long)'u' << 40 | (long)'e' << 32 | (long)'s' << 24 | (long)'t' << 16, + (long)'i' << 56 | (long)'s' << 48 | (long)'i' << 40 | (long)'n' << 32, + (long)'i' << 56 | (long)'u' << 48 | (long)'m' << 40 | (long)'l' << 32, + (long)'k' << 56 | (long)'a' << 48 | (long)'p' << 40 | (long)'p' << 32 | (long)'a' << 24, + (long)'l' << 56 | (long)'A' << 48 | (long)'r' << 40 | (long)'r' << 32, + (long)'l' << 56 | (long)'a' << 48 | (long)'m' << 40 | (long)'b' << 32 | (long)'d' << 24 | (long)'a' << 16, + (long)'l' << 56 | (long)'a' << 48 | (long)'n' << 40 | (long)'g' << 32, + (long)'l' << 56 | (long)'a' << 48 | (long)'q' << 40 | (long)'u' << 32 | (long)'o' << 24, + (long)'l' << 56 | (long)'a' << 48 | (long)'r' << 40 | (long)'r' << 32, + (long)'l' << 56 | (long)'c' << 48 | (long)'e' << 40 | (long)'i' << 32 | (long)'l' << 24, + (long)'l' << 56 | (long)'d' << 48 | (long)'q' << 40 | (long)'u' << 32 | (long)'o' << 24, + (long)'l' << 56 | (long)'e' << 48, + (long)'l' << 56 | (long)'f' << 48 | (long)'l' << 40 | (long)'o' << 32 | (long)'o' << 24 | (long)'r' << 16, + (long)'l' << 56 | (long)'o' << 48 | (long)'w' << 40 | (long)'a' << 32 | (long)'s' << 24 | (long)'t' << 16, + (long)'l' << 56 | (long)'o' << 48 | (long)'z' << 40, + (long)'l' << 56 | (long)'r' << 48 | (long)'m' << 40, + (long)'l' << 56 | (long)'s' << 48 | (long)'a' << 40 | (long)'q' << 32 | (long)'u' << 24 | (long)'o' << 16, + (long)'l' << 56 | (long)'s' << 48 | (long)'q' << 40 | (long)'u' << 32 | (long)'o' << 24, + (long)'l' << 56 | (long)'t' << 48, + (long)'m' << 56 | (long)'a' << 48 | (long)'c' << 40 | (long)'r' << 32, + (long)'m' << 56 | (long)'d' << 48 | (long)'a' << 40 | (long)'s' << 32 | (long)'h' << 24, + (long)'m' << 56 | (long)'i' << 48 | (long)'c' << 40 | (long)'r' << 32 | (long)'o' << 24, + (long)'m' << 56 | (long)'i' << 48 | (long)'d' << 40 | (long)'d' << 32 | (long)'o' << 24 | (long)'t' << 16, + (long)'m' << 56 | (long)'i' << 48 | (long)'n' << 40 | (long)'u' << 32 | (long)'s' << 24, + (long)'m' << 56 | (long)'u' << 48, + (long)'n' << 56 | (long)'a' << 48 | (long)'b' << 40 | (long)'l' << 32 | (long)'a' << 24, + (long)'n' << 56 | (long)'b' << 48 | (long)'s' << 40 | (long)'p' << 32, + (long)'n' << 56 | (long)'d' << 48 | (long)'a' << 40 | (long)'s' << 32 | (long)'h' << 24, + (long)'n' << 56 | (long)'e' << 48, + (long)'n' << 56 | (long)'i' << 48, + (long)'n' << 56 | (long)'o' << 48 | (long)'t' << 40, + (long)'n' << 56 | (long)'o' << 48 | (long)'t' << 40 | (long)'i' << 32 | (long)'n' << 24, + (long)'n' << 56 | (long)'s' << 48 | (long)'u' << 40 | (long)'b' << 32, + (long)'n' << 56 | (long)'t' << 48 | (long)'i' << 40 | (long)'l' << 32 | (long)'d' << 24 | (long)'e' << 16, + (long)'n' << 56 | (long)'u' << 48, + (long)'o' << 56 | (long)'a' << 48 | (long)'c' << 40 | (long)'u' << 32 | (long)'t' << 24 | (long)'e' << 16, + (long)'o' << 56 | (long)'c' << 48 | (long)'i' << 40 | (long)'r' << 32 | (long)'c' << 24, + (long)'o' << 56 | (long)'e' << 48 | (long)'l' << 40 | (long)'i' << 32 | (long)'g' << 24, + (long)'o' << 56 | (long)'g' << 48 | (long)'r' << 40 | (long)'a' << 32 | (long)'v' << 24 | (long)'e' << 16, + (long)'o' << 56 | (long)'l' << 48 | (long)'i' << 40 | (long)'n' << 32 | (long)'e' << 24, + (long)'o' << 56 | (long)'m' << 48 | (long)'e' << 40 | (long)'g' << 32 | (long)'a' << 24, + (long)'o' << 56 | (long)'m' << 48 | (long)'i' << 40 | (long)'c' << 32 | (long)'r' << 24 | (long)'o' << 16 | (long)'n' << 8, + (long)'o' << 56 | (long)'p' << 48 | (long)'l' << 40 | (long)'u' << 32 | (long)'s' << 24, + (long)'o' << 56 | (long)'r' << 48, + (long)'o' << 56 | (long)'r' << 48 | (long)'d' << 40 | (long)'f' << 32, + (long)'o' << 56 | (long)'r' << 48 | (long)'d' << 40 | (long)'m' << 32, + (long)'o' << 56 | (long)'s' << 48 | (long)'l' << 40 | (long)'a' << 32 | (long)'s' << 24 | (long)'h' << 16, + (long)'o' << 56 | (long)'t' << 48 | (long)'i' << 40 | (long)'l' << 32 | (long)'d' << 24 | (long)'e' << 16, + (long)'o' << 56 | (long)'t' << 48 | (long)'i' << 40 | (long)'m' << 32 | (long)'e' << 24 | (long)'s' << 16, + (long)'o' << 56 | (long)'u' << 48 | (long)'m' << 40 | (long)'l' << 32, + (long)'p' << 56 | (long)'a' << 48 | (long)'r' << 40 | (long)'a' << 32, + (long)'p' << 56 | (long)'a' << 48 | (long)'r' << 40 | (long)'t' << 32, + (long)'p' << 56 | (long)'e' << 48 | (long)'r' << 40 | (long)'m' << 32 | (long)'i' << 24 | (long)'l' << 16, + (long)'p' << 56 | (long)'e' << 48 | (long)'r' << 40 | (long)'p' << 32, + (long)'p' << 56 | (long)'h' << 48 | (long)'i' << 40, + (long)'p' << 56 | (long)'i' << 48, + (long)'p' << 56 | (long)'i' << 48 | (long)'v' << 40, + (long)'p' << 56 | (long)'l' << 48 | (long)'u' << 40 | (long)'s' << 32 | (long)'m' << 24 | (long)'n' << 16, + (long)'p' << 56 | (long)'o' << 48 | (long)'u' << 40 | (long)'n' << 32 | (long)'d' << 24, + (long)'p' << 56 | (long)'r' << 48 | (long)'i' << 40 | (long)'m' << 32 | (long)'e' << 24, + (long)'p' << 56 | (long)'r' << 48 | (long)'o' << 40 | (long)'d' << 32, + (long)'p' << 56 | (long)'r' << 48 | (long)'o' << 40 | (long)'p' << 32, + (long)'p' << 56 | (long)'s' << 48 | (long)'i' << 40, + (long)'q' << 56 | (long)'u' << 48 | (long)'o' << 40 | (long)'t' << 32, + (long)'r' << 56 | (long)'A' << 48 | (long)'r' << 40 | (long)'r' << 32, + (long)'r' << 56 | (long)'a' << 48 | (long)'d' << 40 | (long)'i' << 32 | (long)'c' << 24, + (long)'r' << 56 | (long)'a' << 48 | (long)'n' << 40 | (long)'g' << 32, + (long)'r' << 56 | (long)'a' << 48 | (long)'q' << 40 | (long)'u' << 32 | (long)'o' << 24, + (long)'r' << 56 | (long)'a' << 48 | (long)'r' << 40 | (long)'r' << 32, + (long)'r' << 56 | (long)'c' << 48 | (long)'e' << 40 | (long)'i' << 32 | (long)'l' << 24, + (long)'r' << 56 | (long)'d' << 48 | (long)'q' << 40 | (long)'u' << 32 | (long)'o' << 24, + (long)'r' << 56 | (long)'e' << 48 | (long)'a' << 40 | (long)'l' << 32, + (long)'r' << 56 | (long)'e' << 48 | (long)'g' << 40, + (long)'r' << 56 | (long)'f' << 48 | (long)'l' << 40 | (long)'o' << 32 | (long)'o' << 24 | (long)'r' << 16, + (long)'r' << 56 | (long)'h' << 48 | (long)'o' << 40, + (long)'r' << 56 | (long)'l' << 48 | (long)'m' << 40, + (long)'r' << 56 | (long)'s' << 48 | (long)'a' << 40 | (long)'q' << 32 | (long)'u' << 24 | (long)'o' << 16, + (long)'r' << 56 | (long)'s' << 48 | (long)'q' << 40 | (long)'u' << 32 | (long)'o' << 24, + (long)'s' << 56 | (long)'b' << 48 | (long)'q' << 40 | (long)'u' << 32 | (long)'o' << 24, + (long)'s' << 56 | (long)'c' << 48 | (long)'a' << 40 | (long)'r' << 32 | (long)'o' << 24 | (long)'n' << 16, + (long)'s' << 56 | (long)'d' << 48 | (long)'o' << 40 | (long)'t' << 32, + (long)'s' << 56 | (long)'e' << 48 | (long)'c' << 40 | (long)'t' << 32, + (long)'s' << 56 | (long)'h' << 48 | (long)'y' << 40, + (long)'s' << 56 | (long)'i' << 48 | (long)'g' << 40 | (long)'m' << 32 | (long)'a' << 24, + (long)'s' << 56 | (long)'i' << 48 | (long)'g' << 40 | (long)'m' << 32 | (long)'a' << 24 | (long)'f' << 16, + (long)'s' << 56 | (long)'i' << 48 | (long)'m' << 40, + (long)'s' << 56 | (long)'p' << 48 | (long)'a' << 40 | (long)'d' << 32 | (long)'e' << 24 | (long)'s' << 16, + (long)'s' << 56 | (long)'u' << 48 | (long)'b' << 40, + (long)'s' << 56 | (long)'u' << 48 | (long)'b' << 40 | (long)'e' << 32, + (long)'s' << 56 | (long)'u' << 48 | (long)'m' << 40, + (long)'s' << 56 | (long)'u' << 48 | (long)'p' << 40, + (long)'s' << 56 | (long)'u' << 48 | (long)'p' << 40 | (long)'1' << 32, + (long)'s' << 56 | (long)'u' << 48 | (long)'p' << 40 | (long)'2' << 32, + (long)'s' << 56 | (long)'u' << 48 | (long)'p' << 40 | (long)'3' << 32, + (long)'s' << 56 | (long)'u' << 48 | (long)'p' << 40 | (long)'e' << 32, + (long)'s' << 56 | (long)'z' << 48 | (long)'l' << 40 | (long)'i' << 32 | (long)'g' << 24, + (long)'t' << 56 | (long)'a' << 48 | (long)'u' << 40, + (long)'t' << 56 | (long)'h' << 48 | (long)'e' << 40 | (long)'r' << 32 | (long)'e' << 24 | (long)'4' << 16, + (long)'t' << 56 | (long)'h' << 48 | (long)'e' << 40 | (long)'t' << 32 | (long)'a' << 24, + (long)'t' << 56 | (long)'h' << 48 | (long)'e' << 40 | (long)'t' << 32 | (long)'a' << 24 | (long)'s' << 16 | (long)'y' << 8 | (long)'m' << 0, + (long)'t' << 56 | (long)'h' << 48 | (long)'i' << 40 | (long)'n' << 32 | (long)'s' << 24 | (long)'p' << 16, + (long)'t' << 56 | (long)'h' << 48 | (long)'o' << 40 | (long)'r' << 32 | (long)'n' << 24, + (long)'t' << 56 | (long)'i' << 48 | (long)'l' << 40 | (long)'d' << 32 | (long)'e' << 24, + (long)'t' << 56 | (long)'i' << 48 | (long)'m' << 40 | (long)'e' << 32 | (long)'s' << 24, + (long)'t' << 56 | (long)'r' << 48 | (long)'a' << 40 | (long)'d' << 32 | (long)'e' << 24, + (long)'u' << 56 | (long)'A' << 48 | (long)'r' << 40 | (long)'r' << 32, + (long)'u' << 56 | (long)'a' << 48 | (long)'c' << 40 | (long)'u' << 32 | (long)'t' << 24 | (long)'e' << 16, + (long)'u' << 56 | (long)'a' << 48 | (long)'r' << 40 | (long)'r' << 32, + (long)'u' << 56 | (long)'c' << 48 | (long)'i' << 40 | (long)'r' << 32 | (long)'c' << 24, + (long)'u' << 56 | (long)'g' << 48 | (long)'r' << 40 | (long)'a' << 32 | (long)'v' << 24 | (long)'e' << 16, + (long)'u' << 56 | (long)'m' << 48 | (long)'l' << 40, + (long)'u' << 56 | (long)'p' << 48 | (long)'s' << 40 | (long)'i' << 32 | (long)'h' << 24, + (long)'u' << 56 | (long)'p' << 48 | (long)'s' << 40 | (long)'i' << 32 | (long)'l' << 24 | (long)'o' << 16 | (long)'n' << 8, + (long)'u' << 56 | (long)'u' << 48 | (long)'m' << 40 | (long)'l' << 32, + (long)'w' << 56 | (long)'e' << 48 | (long)'i' << 40 | (long)'e' << 32 | (long)'r' << 24 | (long)'p' << 16, + (long)'x' << 56 | (long)'i' << 48, + (long)'y' << 56 | (long)'a' << 48 | (long)'c' << 40 | (long)'u' << 32 | (long)'t' << 24 | (long)'e' << 16, + (long)'y' << 56 | (long)'e' << 48 | (long)'n' << 40, + (long)'y' << 56 | (long)'u' << 48 | (long)'m' << 40 | (long)'l' << 32, + (long)'z' << 56 | (long)'e' << 48 | (long)'t' << 40 | (long)'a' << 32, + (long)'z' << 56 | (long)'w' << 48 | (long)'j' << 40, + (long)'z' << 56 | (long)'w' << 48 | (long)'n' << 40 | (long)'j' << 32 + }; + + static readonly char[] entities_values = new char[] { + '\u00C6', + '\u00C1', + '\u00C2', + '\u00C0', + '\u0391', + '\u00C5', + '\u00C3', + '\u00C4', + '\u0392', + '\u00C7', + '\u03A7', + '\u2021', + '\u0394', + '\u00D0', + '\u00C9', + '\u00CA', + '\u00C8', + '\u0395', + '\u0397', + '\u00CB', + '\u0393', + '\u00CD', + '\u00CE', + '\u00CC', + '\u0399', + '\u00CF', + '\u039A', + '\u039B', + '\u039C', + '\u00D1', + '\u039D', + '\u0152', + '\u00D3', + '\u00D4', + '\u00D2', + '\u03A9', + '\u039F', + '\u00D8', + '\u00D5', + '\u00D6', + '\u03A6', + '\u03A0', + '\u2033', + '\u03A8', + '\u03A1', + '\u0160', + '\u03A3', + '\u00DE', + '\u03A4', + '\u0398', + '\u00DA', + '\u00DB', + '\u00D9', + '\u03A5', + '\u00DC', + '\u039E', + '\u00DD', + '\u0178', + '\u0396', + '\u00E1', + '\u00E2', + '\u00B4', + '\u00E6', + '\u00E0', + '\u2135', + '\u03B1', + '\u0026', + '\u2227', + '\u2220', + '\u0027', + '\u00E5', + '\u2248', + '\u00E3', + '\u00E4', + '\u201E', + '\u03B2', + '\u00A6', + '\u2022', + '\u2229', + '\u00E7', + '\u00B8', + '\u00A2', + '\u03C7', + '\u02C6', + '\u2663', + '\u2245', + '\u00A9', + '\u21B5', + '\u222A', + '\u00A4', + '\u21D3', + '\u2020', + '\u2193', + '\u00B0', + '\u03B4', + '\u2666', + '\u00F7', + '\u00E9', + '\u00EA', + '\u00E8', + '\u2205', + '\u2003', + '\u2002', + '\u03B5', + '\u2261', + '\u03B7', + '\u00F0', + '\u00EB', + '\u20AC', + '\u2203', + '\u0192', + '\u2200', + '\u00BD', + '\u00BC', + '\u00BE', + '\u2044', + '\u03B3', + '\u2265', + '\u003E', + '\u21D4', + '\u2194', + '\u2665', + '\u2026', + '\u00ED', + '\u00EE', + '\u00A1', + '\u00EC', + '\u2111', + '\u221E', + '\u222B', + '\u03B9', + '\u00BF', + '\u2208', + '\u00EF', + '\u03BA', + '\u21D0', + '\u03BB', + '\u2329', + '\u00AB', + '\u2190', + '\u2308', + '\u201C', + '\u2264', + '\u230A', + '\u2217', + '\u25CA', + '\u200E', + '\u2039', + '\u2018', + '\u003C', + '\u00AF', + '\u2014', + '\u00B5', + '\u00B7', + '\u2212', + '\u03BC', + '\u2207', + '\u00A0', + '\u2013', + '\u2260', + '\u220B', + '\u00AC', + '\u2209', + '\u2284', + '\u00F1', + '\u03BD', + '\u00F3', + '\u00F4', + '\u0153', + '\u00F2', + '\u203E', + '\u03C9', + '\u03BF', + '\u2295', + '\u2228', + '\u00AA', + '\u00BA', + '\u00F8', + '\u00F5', + '\u2297', + '\u00F6', + '\u00B6', + '\u2202', + '\u2030', + '\u22A5', + '\u03C6', + '\u03C0', + '\u03D6', + '\u00B1', + '\u00A3', + '\u2032', + '\u220F', + '\u221D', + '\u03C8', + '\u0022', + '\u21D2', + '\u221A', + '\u232A', + '\u00BB', + '\u2192', + '\u2309', + '\u201D', + '\u211C', + '\u00AE', + '\u230B', + '\u03C1', + '\u200F', + '\u203A', + '\u2019', + '\u201A', + '\u0161', + '\u22C5', + '\u00A7', + '\u00AD', + '\u03C3', + '\u03C2', + '\u223C', + '\u2660', + '\u2282', + '\u2286', + '\u2211', + '\u2283', + '\u00B9', + '\u00B2', + '\u00B3', + '\u2287', + '\u00DF', + '\u03C4', + '\u2234', + '\u03B8', + '\u03D1', + '\u2009', + '\u00FE', + '\u02DC', + '\u00D7', + '\u2122', + '\u21D1', + '\u00FA', + '\u2191', + '\u00FB', + '\u00F9', + '\u00A8', + '\u03D2', + '\u03C5', + '\u00FC', + '\u2118', + '\u03BE', + '\u00FD', + '\u00A5', + '\u00FF', + '\u03B6', + '\u200D', + '\u200C' + }; + + #region Methods + + static void WriteCharBytes(IList buf, char ch, Encoding e) + { + if (ch > 255) + { + foreach (byte b in e.GetBytes(new char[] { ch })) + buf.Add(b); + } + else + buf.Add((byte)ch); + } + + public static string UrlDecode(string s, Encoding e) + { + if (null == s) + return null; + + if (s.IndexOf('%') == -1 && s.IndexOf('+') == -1) + return s; + + if (e == null) + e = Encoding.UTF8; + + long len = s.Length; + var bytes = new List(); + int xchar; + char ch; + + for (int i = 0; i < len; i++) + { + ch = s[i]; + if (ch == '%' && i + 2 < len && s[i + 1] != '%') + { + if (s[i + 1] == 'u' && i + 5 < len) + { + // unicode hex sequence + xchar = GetChar(s, i + 2, 4); + if (xchar != -1) + { + WriteCharBytes(bytes, (char)xchar, e); + i += 5; + } + else + WriteCharBytes(bytes, '%', e); + } + else if ((xchar = GetChar(s, i + 1, 2)) != -1) + { + WriteCharBytes(bytes, (char)xchar, e); + i += 2; + } + else + { + WriteCharBytes(bytes, '%', e); + } + continue; + } + + if (ch == '+') + WriteCharBytes(bytes, ' ', e); + else + WriteCharBytes(bytes, ch, e); + } + + byte[] buf = bytes.ToArray(); + bytes = null; + return e.GetString(buf); + + } + + static int GetInt(byte b) + { + char c = (char)b; + if (c >= '0' && c <= '9') + return c - '0'; + + if (c >= 'a' && c <= 'f') + return c - 'a' + 10; + + if (c >= 'A' && c <= 'F') + return c - 'A' + 10; + + return -1; + } + + static int GetChar(string str, int offset, int length) + { + int val = 0; + int end = length + offset; + for (int i = offset; i < end; i++) + { + char c = str[i]; + if (c > 127) + return -1; + + int current = GetInt((byte)c); + if (current == -1) + return -1; + val = (val << 4) + current; + } + + return val; + } + + static bool TryConvertKeyToEntity(string key, out char value) + { + var token = CalculateKeyValue(key); + if (token == 0) + { + value = '\0'; + return false; + } + + var idx = Array.BinarySearch(entities, token); + if (idx < 0) + { + value = '\0'; + return false; + } + + value = entities_values[idx]; + return true; + } + + static long CalculateKeyValue(string s) + { + if (s.Length > 8) + return 0; + + long key = 0; + for (int i = 0; i < s.Length; ++i) + { + long ch = s[i]; + if (ch > 'z' || ch < '0') + return 0; + + key |= ch << ((7 - i) * 8); + } + + return key; + } + + /// + /// Decodes an HTML-encoded string and returns the decoded string. + /// + /// The HTML string to decode. + /// The decoded text. + public static string HtmlDecode(string s) + { + if (s == null) + throw new ArgumentNullException("s"); + + if (s.IndexOf('&') == -1) + return s; + + StringBuilder entity = new StringBuilder(); + StringBuilder output = new StringBuilder(); + int len = s.Length; + // 0 -> nothing, + // 1 -> right after '&' + // 2 -> between '&' and ';' but no '#' + // 3 -> '#' found after '&' and getting numbers + int state = 0; + int number = 0; + int digit_start = 0; + bool hex_number = false; + + for (int i = 0; i < len; i++) + { + char c = s[i]; + if (state == 0) + { + if (c == '&') + { + entity.Append(c); + state = 1; + } + else + { + output.Append(c); + } + continue; + } + + if (c == '&') + { + state = 1; + if (digit_start > 0) + { + entity.Append(s, digit_start, i - digit_start); + digit_start = 0; + } + + output.Append(entity.ToString()); + entity.Length = 0; + entity.Append('&'); + continue; + } + + switch (state) + { + case 1: + if (c == ';') + { + state = 0; + output.Append(entity.ToString()); + output.Append(c); + entity.Length = 0; + break; + } + + number = 0; + hex_number = false; + if (c != '#') + { + state = 2; + } + else + { + state = 3; + } + entity.Append(c); + + break; + case 2: + entity.Append(c); + if (c == ';') + { + string key = entity.ToString(); + state = 0; + entity.Length = 0; + + if (key.Length > 1) + { + var skey = key.Substring(1, key.Length - 2); + if (TryConvertKeyToEntity(skey, out c)) + { + output.Append(c); + break; + } + } + + output.Append(key); + } + + break; + case 3: + if (c == ';') + { + if (number < 0x10000) + { + output.Append((char)number); + } + else + { + output.Append((char)(0xd800 + ((number - 0x10000) >> 10))); + output.Append((char)(0xdc00 + ((number - 0x10000) & 0x3ff))); + } + state = 0; + entity.Length = 0; + digit_start = 0; + break; + } + + if (c == 'x' || c == 'X' && !hex_number) + { + digit_start = i; + hex_number = true; + break; + } + + if (Char.IsDigit(c)) + { + if (digit_start == 0) + digit_start = i; + + number = number * (hex_number ? 16 : 10) + ((int)c - '0'); + break; + } + + if (hex_number) + { + if (c >= 'a' && c <= 'f') + { + number = number * 16 + 10 + ((int)c - 'a'); + break; + } + if (c >= 'A' && c <= 'F') + { + number = number * 16 + 10 + ((int)c - 'A'); + break; + } + } + + state = 2; + if (digit_start > 0) + { + entity.Append(s, digit_start, i - digit_start); + digit_start = 0; + } + + entity.Append(c); + break; + } + } + + if (entity.Length > 0) + { + output.Append(entity); + } + else if (digit_start > 0) + { + output.Append(s, digit_start, s.Length - digit_start); + } + return output.ToString(); + } + + public static NameValueCollection ParseQueryString(string query) + { + return ParseQueryString(query, Encoding.UTF8); + } + + public static NameValueCollection ParseQueryString(string query, Encoding encoding) + { + if (query == null) + throw new ArgumentNullException("query"); + if (encoding == null) + throw new ArgumentNullException("encoding"); + if (query.Length == 0 || (query.Length == 1 && query[0] == '?')) + return new NameValueCollection(); + if (query[0] == '?') + query = query.Substring(1); + + NameValueCollection result = new HttpQSCollection(); + ParseQueryString(query, encoding, result); + return result; + } + + internal static void ParseQueryString(string query, Encoding encoding, NameValueCollection result) + { + if (query.Length == 0) + return; + + string decoded = HtmlDecode(query); + int decodedLength = decoded.Length; + int namePos = 0; + bool first = true; + while (namePos <= decodedLength) + { + int valuePos = -1, valueEnd = -1; + for (int q = namePos; q < decodedLength; q++) + { + if (valuePos == -1 && decoded[q] == '=') + { + valuePos = q + 1; + } + else if (decoded[q] == '&') + { + valueEnd = q; + break; + } + } + + if (first) + { + first = false; + if (decoded[namePos] == '?') + namePos++; + } + + string name, value; + if (valuePos == -1) + { + name = null; + valuePos = namePos; + } + else + { + name = UrlDecode(decoded.Substring(namePos, valuePos - namePos - 1), encoding); + } + if (valueEnd < 0) + { + namePos = -1; + valueEnd = decoded.Length; + } + else + { + namePos = valueEnd + 1; + } + value = UrlDecode(decoded.Substring(valuePos, valueEnd - valuePos), encoding); + + result.Add(name, value); + if (namePos == -1) + break; + } + } + #endregion // Methods + } +} diff --git a/MediaBrowser.Server.Implementations/HttpServer/SocketSharp/WebSocketSharpRequest.cs b/MediaBrowser.Server.Implementations/HttpServer/SocketSharp/WebSocketSharpRequest.cs index 54c27cf0a2..b3fbd2d1d4 100644 --- a/MediaBrowser.Server.Implementations/HttpServer/SocketSharp/WebSocketSharpRequest.cs +++ b/MediaBrowser.Server.Implementations/HttpServer/SocketSharp/WebSocketSharpRequest.cs @@ -2,6 +2,7 @@ using System.Collections.Generic; using System.IO; using System.Text; +using System.Web; using Funq; using MediaBrowser.Model.Logging; using ServiceStack; @@ -236,7 +237,7 @@ namespace MediaBrowser.Server.Implementations.HttpServer.SocketSharp private NameValueCollectionWrapper queryString; public INameValueCollection QueryString { - get { return queryString ?? (queryString = new NameValueCollectionWrapper(HttpUtility.ParseQueryString(request.Url.Query))); } + get { return queryString ?? (queryString = new NameValueCollectionWrapper(MyHttpUtility.ParseQueryString(request.Url.Query))); } } private NameValueCollectionWrapper formData; diff --git a/MediaBrowser.Server.Implementations/Library/UserManager.cs b/MediaBrowser.Server.Implementations/Library/UserManager.cs index 3c29cf15d5..cf1853c5e7 100644 --- a/MediaBrowser.Server.Implementations/Library/UserManager.cs +++ b/MediaBrowser.Server.Implementations/Library/UserManager.cs @@ -403,10 +403,7 @@ namespace MediaBrowser.Server.Implementations.Library try { - _dtoServiceFactory().AttachPrimaryImageAspectRatio(dto, user, new List - { - ItemFields.PrimaryImageAspectRatio - }); + _dtoServiceFactory().AttachPrimaryImageAspectRatio(dto, user); } catch (Exception ex) { diff --git a/MediaBrowser.Server.Implementations/LiveTv/Listings/Emby/EmbyListings.cs b/MediaBrowser.Server.Implementations/LiveTv/Listings/Emby/EmbyListings.cs deleted file mode 100644 index ae441b44e0..0000000000 --- a/MediaBrowser.Server.Implementations/LiveTv/Listings/Emby/EmbyListings.cs +++ /dev/null @@ -1,59 +0,0 @@ -using MediaBrowser.Common.Net; -using MediaBrowser.Controller.LiveTv; -using MediaBrowser.Model.Dto; -using MediaBrowser.Model.LiveTv; -using System; -using System.Collections.Generic; -using System.Threading; -using System.Threading.Tasks; -using MediaBrowser.Model.Serialization; - -namespace MediaBrowser.Server.Implementations.LiveTv.Listings.Emby -{ - public class EmbyGuide : IListingsProvider - { - private readonly IHttpClient _httpClient; - private readonly IJsonSerializer _jsonSerializer; - - public EmbyGuide(IHttpClient httpClient, IJsonSerializer jsonSerializer) - { - _httpClient = httpClient; - _jsonSerializer = jsonSerializer; - } - - public string Name - { - get { return "Emby Guide"; } - } - - public string Type - { - get { return "emby"; } - } - - public Task> GetProgramsAsync(ListingsProviderInfo info, string channelNumber, string channelName, DateTime startDateUtc, DateTime endDateUtc, CancellationToken cancellationToken) - { - return GetListingsProvider(info.Country).GetProgramsAsync(info, channelNumber, startDateUtc, endDateUtc, cancellationToken); - } - - public Task AddMetadata(ListingsProviderInfo info, List channels, CancellationToken cancellationToken) - { - return GetListingsProvider(info.Country).AddMetadata(info, channels, cancellationToken); - } - - public Task Validate(ListingsProviderInfo info, bool validateLogin, bool validateListings) - { - return GetListingsProvider(info.Country).Validate(info, validateLogin, validateListings); - } - - public Task> GetLineups(ListingsProviderInfo info, string country, string location) - { - return GetListingsProvider(country).GetLineups(country, location); - } - - private IEmbyListingProvider GetListingsProvider(string country) - { - return new EmbyListingsNorthAmerica(_httpClient, _jsonSerializer); - } - } -} diff --git a/MediaBrowser.Server.Implementations/LiveTv/Listings/Emby/EmbyListingsNorthAmerica.cs b/MediaBrowser.Server.Implementations/LiveTv/Listings/Emby/EmbyListingsNorthAmerica.cs deleted file mode 100644 index 2993740d63..0000000000 --- a/MediaBrowser.Server.Implementations/LiveTv/Listings/Emby/EmbyListingsNorthAmerica.cs +++ /dev/null @@ -1,366 +0,0 @@ -using MediaBrowser.Common.Net; -using MediaBrowser.Controller.LiveTv; -using MediaBrowser.Model.Dto; -using MediaBrowser.Model.LiveTv; -using MediaBrowser.Model.Serialization; -using System; -using System.Collections.Generic; -using System.Globalization; -using System.IO; -using System.Linq; -using System.Threading; -using System.Threading.Tasks; - -namespace MediaBrowser.Server.Implementations.LiveTv.Listings.Emby -{ - public class EmbyListingsNorthAmerica : IEmbyListingProvider - { - private readonly IHttpClient _httpClient; - private readonly IJsonSerializer _jsonSerializer; - - public EmbyListingsNorthAmerica(IHttpClient httpClient, IJsonSerializer jsonSerializer) - { - _httpClient = httpClient; - _jsonSerializer = jsonSerializer; - } - - public async Task> GetProgramsAsync(ListingsProviderInfo info, string channelNumber, DateTime startDateUtc, DateTime endDateUtc, CancellationToken cancellationToken) - { - channelNumber = NormalizeNumber(channelNumber); - - var url = "https://data.emby.media/service/listings?id=" + info.ListingsId; - - // Normalize - startDateUtc = startDateUtc.Date; - endDateUtc = startDateUtc.AddDays(7); - - url += "&start=" + startDateUtc.ToString("s", CultureInfo.InvariantCulture) + "Z"; - url += "&end=" + endDateUtc.ToString("s", CultureInfo.InvariantCulture) + "Z"; - - var response = await GetResponse(url).ConfigureAwait(false); - - return response.Where(i => IncludeInResults(i, channelNumber)).Select(GetProgramInfo).OrderBy(i => i.StartDate); - } - - private ProgramInfo GetProgramInfo(ListingInfo info) - { - var showType = info.showType ?? string.Empty; - - var program = new ProgramInfo - { - Id = info.listingID.ToString(CultureInfo.InvariantCulture), - Name = GetStringValue(info.showName), - HomePageUrl = GetStringValue(info.webLink), - Overview = info.description, - IsHD = info.hd, - IsLive = info.live, - IsPremiere = info.seasonPremiere || info.seriesPremiere, - IsMovie = showType.IndexOf("Movie", StringComparison.OrdinalIgnoreCase) != -1, - IsKids = showType.IndexOf("Children", StringComparison.OrdinalIgnoreCase) != -1, - IsNews = showType.IndexOf("News", StringComparison.OrdinalIgnoreCase) != -1, - IsSports = showType.IndexOf("Sports", StringComparison.OrdinalIgnoreCase) != -1 - }; - - if (!string.IsNullOrWhiteSpace(info.listDateTime)) - { - program.StartDate = DateTime.ParseExact(info.listDateTime, "yyyy'-'MM'-'dd' 'HH':'mm':'ss", CultureInfo.InvariantCulture); - program.StartDate = DateTime.SpecifyKind(program.StartDate, DateTimeKind.Utc); - program.EndDate = program.StartDate.AddMinutes(info.duration); - } - - if (info.starRating > 0) - { - program.CommunityRating = info.starRating*2; - } - - if (!string.IsNullOrWhiteSpace(info.rating)) - { - // They don't have dashes so try to normalize - program.OfficialRating = info.rating.Replace("TV", "TV-").Replace("--", "-"); - - var invalid = new[] { "N/A", "Approved", "Not Rated" }; - if (invalid.Contains(program.OfficialRating, StringComparer.OrdinalIgnoreCase)) - { - program.OfficialRating = null; - } - } - - if (!string.IsNullOrWhiteSpace(info.year)) - { - program.ProductionYear = int.Parse(info.year, CultureInfo.InvariantCulture); - } - - if (info.showID > 0) - { - program.ShowId = info.showID.ToString(CultureInfo.InvariantCulture); - } - - if (info.seriesID > 0) - { - program.SeriesId = info.seriesID.ToString(CultureInfo.InvariantCulture); - program.IsSeries = true; - program.IsRepeat = info.repeat; - - program.EpisodeTitle = GetStringValue(info.episodeTitle); - - if (string.Equals(program.Name, program.EpisodeTitle, StringComparison.OrdinalIgnoreCase)) - { - program.EpisodeTitle = null; - } - } - - if (info.starRating > 0) - { - program.CommunityRating = info.starRating * 2; - } - - if (string.Equals(info.showName, "Movie", StringComparison.OrdinalIgnoreCase)) - { - // Sometimes the movie title will be in here - if (!string.IsNullOrWhiteSpace(info.episodeTitle)) - { - program.Name = info.episodeTitle; - } - } - - return program; - } - - private string GetStringValue(string s) - { - return string.IsNullOrWhiteSpace(s) ? null : s; - } - - private bool IncludeInResults(ListingInfo info, string itemNumber) - { - if (string.Equals(itemNumber, NormalizeNumber(info.number), StringComparison.OrdinalIgnoreCase)) - { - return true; - } - - var channelNumber = info.channelNumber.ToString(CultureInfo.InvariantCulture); - if (info.subChannelNumber > 0) - { - channelNumber += "." + info.subChannelNumber.ToString(CultureInfo.InvariantCulture); - } - - return string.Equals(channelNumber, itemNumber, StringComparison.OrdinalIgnoreCase); - } - - public async Task AddMetadata(ListingsProviderInfo info, List channels, CancellationToken cancellationToken) - { - var response = await GetResponse("https://data.emby.media/service/lineups?id=" + info.ListingsId).ConfigureAwait(false); - - foreach (var channel in channels) - { - var station = response.stations.FirstOrDefault(i => - { - var itemNumber = NormalizeNumber(channel.Number); - - if (string.Equals(itemNumber, NormalizeNumber(i.number), StringComparison.OrdinalIgnoreCase)) - { - return true; - } - - var channelNumber = i.channelNumber.ToString(CultureInfo.InvariantCulture); - if (i.subChannelNumber > 0) - { - channelNumber += "." + i.subChannelNumber.ToString(CultureInfo.InvariantCulture); - } - - return string.Equals(channelNumber, itemNumber, StringComparison.OrdinalIgnoreCase); - }); - - if (station != null) - { - //channel.Name = station.name; - - if (!string.IsNullOrWhiteSpace(station.logoFilename)) - { - channel.HasImage = true; - channel.ImageUrl = "http://cdn.tvpassport.com/image/station/100x100/" + station.logoFilename; - } - } - } - } - - private string NormalizeNumber(string number) - { - return number.Replace('-', '.'); - } - - public Task Validate(ListingsProviderInfo info, bool validateLogin, bool validateListings) - { - return Task.FromResult(true); - } - - public async Task> GetLineups(string country, string location) - { - // location = postal code - var response = await GetResponse("https://data.emby.media/service/lineups?postalCode=" + location).ConfigureAwait(false); - - return response.Select(i => new NameIdPair - { - Name = GetName(i), - Id = i.lineupID - - }).OrderBy(i => i.Name).ToList(); - } - - private string GetName(LineupInfo info) - { - var name = info.lineupName; - - if (string.Equals(info.lineupType, "cab", StringComparison.OrdinalIgnoreCase)) - { - name += " - Cable"; - } - else if (string.Equals(info.lineupType, "sat", StringComparison.OrdinalIgnoreCase)) - { - name += " - SAT"; - } - else if (string.Equals(info.lineupType, "ota", StringComparison.OrdinalIgnoreCase)) - { - name += " - OTA"; - } - - return name; - } - - private async Task GetResponse(string url, Func filter = null) - where T : class - { - using (var stream = await _httpClient.Get(new HttpRequestOptions - { - Url = url, - CacheLength = TimeSpan.FromDays(1), - CacheMode = CacheMode.Unconditional - - }).ConfigureAwait(false)) - { - using (var reader = new StreamReader(stream)) - { - var path = await reader.ReadToEndAsync().ConfigureAwait(false); - - using (var secondStream = await _httpClient.Get(new HttpRequestOptions - { - Url = "https://www.mb3admin.com" + path, - CacheLength = TimeSpan.FromDays(1), - CacheMode = CacheMode.Unconditional - - }).ConfigureAwait(false)) - { - return ParseResponse(secondStream, filter); - } - } - } - } - - private T ParseResponse(Stream response, Func filter) - { - using (var reader = new StreamReader(response)) - { - var json = reader.ReadToEnd(); - - if (filter != null) - { - json = filter(json); - } - - return _jsonSerializer.DeserializeFromString(json); - } - } - - private class LineupInfo - { - public string lineupID { get; set; } - public string lineupName { get; set; } - public string lineupType { get; set; } - public string providerID { get; set; } - public string providerName { get; set; } - public string serviceArea { get; set; } - public string country { get; set; } - } - - private class Station - { - public string number { get; set; } - public int channelNumber { get; set; } - public int subChannelNumber { get; set; } - public int stationID { get; set; } - public string name { get; set; } - public string callsign { get; set; } - public string network { get; set; } - public string stationType { get; set; } - public int NTSC_TSID { get; set; } - public int DTV_TSID { get; set; } - public string webLink { get; set; } - public string logoFilename { get; set; } - } - - private class LineupDetailResponse - { - public string lineupID { get; set; } - public string lineupName { get; set; } - public string lineupType { get; set; } - public string providerID { get; set; } - public string providerName { get; set; } - public string serviceArea { get; set; } - public string country { get; set; } - public List stations { get; set; } - } - - private class ListingInfo - { - public string number { get; set; } - public int channelNumber { get; set; } - public int subChannelNumber { get; set; } - public int stationID { get; set; } - public string name { get; set; } - public string callsign { get; set; } - public string network { get; set; } - public string stationType { get; set; } - public string webLink { get; set; } - public string logoFilename { get; set; } - public int listingID { get; set; } - public string listDateTime { get; set; } - public int duration { get; set; } - public int showID { get; set; } - public int seriesID { get; set; } - public string showName { get; set; } - public string episodeTitle { get; set; } - public string episodeNumber { get; set; } - public int parts { get; set; } - public int partNum { get; set; } - public bool seriesPremiere { get; set; } - public bool seasonPremiere { get; set; } - public bool seriesFinale { get; set; } - public bool seasonFinale { get; set; } - public bool repeat { get; set; } - public bool @new { get; set; } - public string rating { get; set; } - public bool captioned { get; set; } - public bool educational { get; set; } - public bool blackWhite { get; set; } - public bool subtitled { get; set; } - public bool live { get; set; } - public bool hd { get; set; } - public bool descriptiveVideo { get; set; } - public bool inProgress { get; set; } - public string showTypeID { get; set; } - public int breakoutLevel { get; set; } - public string showType { get; set; } - public string year { get; set; } - public string guest { get; set; } - public string cast { get; set; } - public string director { get; set; } - public int starRating { get; set; } - public string description { get; set; } - public string league { get; set; } - public string team1 { get; set; } - public string team2 { get; set; } - public string @event { get; set; } - public string location { get; set; } - } - } -} diff --git a/MediaBrowser.Server.Implementations/LiveTv/Listings/Emby/IEmbyListingProvider.cs b/MediaBrowser.Server.Implementations/LiveTv/Listings/Emby/IEmbyListingProvider.cs deleted file mode 100644 index 95c22b9869..0000000000 --- a/MediaBrowser.Server.Implementations/LiveTv/Listings/Emby/IEmbyListingProvider.cs +++ /dev/null @@ -1,18 +0,0 @@ -using MediaBrowser.Controller.LiveTv; -using MediaBrowser.Model.Dto; -using MediaBrowser.Model.LiveTv; -using System; -using System.Collections.Generic; -using System.Threading; -using System.Threading.Tasks; - -namespace MediaBrowser.Server.Implementations.LiveTv.Listings.Emby -{ - public interface IEmbyListingProvider - { - Task> GetProgramsAsync(ListingsProviderInfo info, string channelNumber, DateTime startDateUtc, DateTime endDateUtc, CancellationToken cancellationToken); - Task AddMetadata(ListingsProviderInfo info, List channels, CancellationToken cancellationToken); - Task Validate(ListingsProviderInfo info, bool validateLogin, bool validateListings); - Task> GetLineups(string country, string location); - } -} diff --git a/MediaBrowser.Server.Implementations/LiveTv/Listings/SchedulesDirect.cs b/MediaBrowser.Server.Implementations/LiveTv/Listings/SchedulesDirect.cs index 85d3ffdbaa..87d7ff3eba 100644 --- a/MediaBrowser.Server.Implementations/LiveTv/Listings/SchedulesDirect.cs +++ b/MediaBrowser.Server.Implementations/LiveTv/Listings/SchedulesDirect.cs @@ -114,7 +114,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv.Listings var requestString = _jsonSerializer.SerializeToString(requestList); _logger.Debug("Request string for schedules is: " + requestString); httpOptions.RequestContent = requestString; - using (var response = await Post(httpOptions).ConfigureAwait(false)) + using (var response = await Post(httpOptions, true, info).ConfigureAwait(false)) { StreamReader reader = new StreamReader(response.Content); string responseString = reader.ReadToEnd(); @@ -138,7 +138,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv.Listings var requestBody = "[\"" + string.Join("\", \"", programsID) + "\"]"; httpOptions.RequestContent = requestBody; - using (var innerResponse = await Post(httpOptions).ConfigureAwait(false)) + using (var innerResponse = await Post(httpOptions, true, info).ConfigureAwait(false)) { StreamReader innerReader = new StreamReader(innerResponse.Content); responseString = innerReader.ReadToEnd(); @@ -148,7 +148,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv.Listings responseString); var programDict = programDetails.ToDictionary(p => p.programID, y => y); - var images = await GetImageForPrograms(programDetails.Where(p => p.hasImageArtwork).Select(p => p.programID).ToList(), cancellationToken); + var images = await GetImageForPrograms(info, programDetails.Where(p => p.hasImageArtwork).Select(p => p.programID).ToList(), cancellationToken); var schedules = dailySchedules.SelectMany(d => d.programs); foreach (ScheduleDirect.Program schedule in schedules) @@ -229,7 +229,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv.Listings httpOptions.RequestHeaders["token"] = token; - using (var response = await Get(httpOptions).ConfigureAwait(false)) + using (var response = await Get(httpOptions, true, info).ConfigureAwait(false)) { var root = _jsonSerializer.DeserializeFromStream(response); _logger.Info("Found " + root.map.Count() + " channels on the lineup on ScheduleDirect"); @@ -447,7 +447,9 @@ namespace MediaBrowser.Server.Implementations.LiveTv.Listings return url; } - private async Task> GetImageForPrograms(List programIds, + private async Task> GetImageForPrograms( + ListingsProviderInfo info, + List programIds, CancellationToken cancellationToken) { var imageIdString = "["; @@ -472,7 +474,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv.Listings TimeoutMs = 60000 }; List images; - using (var innerResponse2 = await Post(httpOptions).ConfigureAwait(false)) + using (var innerResponse2 = await Post(httpOptions, true, info).ConfigureAwait(false)) { images = _jsonSerializer.DeserializeFromStream>( innerResponse2.Content); @@ -504,7 +506,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv.Listings try { - using (Stream responce = await Get(options).ConfigureAwait(false)) + using (Stream responce = await Get(options, false, info).ConfigureAwait(false)) { var root = _jsonSerializer.DeserializeFromStream>(responce); @@ -606,30 +608,58 @@ namespace MediaBrowser.Server.Implementations.LiveTv.Listings } } - private async Task Post(HttpRequestOptions options) + private async Task Post(HttpRequestOptions options, + bool enableRetry, + ListingsProviderInfo providerInfo) { try { return await _httpClient.Post(options).ConfigureAwait(false); - } - catch - { - _tokens.Clear(); - throw; - } + } + catch (HttpException ex) + { + _tokens.Clear(); + + if (!ex.StatusCode.HasValue || (int)ex.StatusCode.Value >= 500) + { + enableRetry = false; + } + + if (!enableRetry) { + throw; + } + } + + var newToken = await GetToken (providerInfo, options.CancellationToken).ConfigureAwait (false); + options.RequestHeaders ["token"] = newToken; + return await Post (options, false, providerInfo).ConfigureAwait (false); } - private async Task Get(HttpRequestOptions options) + private async Task Get(HttpRequestOptions options, + bool enableRetry, + ListingsProviderInfo providerInfo) { try { return await _httpClient.Get(options).ConfigureAwait(false); - } - catch - { - _tokens.Clear(); - throw; - } + } + catch (HttpException ex) + { + _tokens.Clear(); + + if (!ex.StatusCode.HasValue || (int)ex.StatusCode.Value >= 500) + { + enableRetry = false; + } + + if (!enableRetry) { + throw; + } + } + + var newToken = await GetToken (providerInfo, options.CancellationToken).ConfigureAwait (false); + options.RequestHeaders ["token"] = newToken; + return await Get (options, false, providerInfo).ConfigureAwait (false); } private async Task GetTokenInternal(string username, string password, @@ -646,7 +676,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv.Listings //_logger.Info("Obtaining token from Schedules Direct from addres: " + httpOptions.Url + " with body " + // httpOptions.RequestContent); - using (var responce = await Post(httpOptions).ConfigureAwait(false)) + using (var responce = await Post(httpOptions, false, null).ConfigureAwait(false)) { var root = _jsonSerializer.DeserializeFromStream(responce.Content); if (root.message == "OK") @@ -728,7 +758,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv.Listings try { - using (var response = await Get(options).ConfigureAwait(false)) + using (var response = await Get(options, false, null).ConfigureAwait(false)) { var root = _jsonSerializer.DeserializeFromStream(response); diff --git a/MediaBrowser.Server.Implementations/LiveTv/LiveTvDtoService.cs b/MediaBrowser.Server.Implementations/LiveTv/LiveTvDtoService.cs index 9ffd8a500e..04f99cdce9 100644 --- a/MediaBrowser.Server.Implementations/LiveTv/LiveTvDtoService.cs +++ b/MediaBrowser.Server.Implementations/LiveTv/LiveTvDtoService.cs @@ -231,10 +231,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv { dto.ImageTags[ImageType.Primary] = imageTag; - _dtoService.AttachPrimaryImageAspectRatio(dto, info, new List - { - ItemFields.PrimaryImageAspectRatio - }); + _dtoService.AttachPrimaryImageAspectRatio(dto, info); } if (currentProgram != null) diff --git a/MediaBrowser.Server.Implementations/LiveTv/TunerHosts/SatIp.cs b/MediaBrowser.Server.Implementations/LiveTv/TunerHosts/SatIp.cs new file mode 100644 index 0000000000..ecd2864c55 --- /dev/null +++ b/MediaBrowser.Server.Implementations/LiveTv/TunerHosts/SatIp.cs @@ -0,0 +1,54 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading; +using System.Threading.Tasks; +using MediaBrowser.Common.Configuration; +using MediaBrowser.Controller.LiveTv; +using MediaBrowser.Controller.MediaEncoding; +using MediaBrowser.Model.Dto; +using MediaBrowser.Model.LiveTv; +using MediaBrowser.Model.Logging; +using MediaBrowser.Model.Serialization; + +namespace MediaBrowser.Server.Implementations.LiveTv.TunerHosts +{ + public class SatIp : BaseTunerHost + { + public SatIp(IConfigurationManager config, ILogger logger, IJsonSerializer jsonSerializer, IMediaEncoder mediaEncoder) + : base(config, logger, jsonSerializer, mediaEncoder) + { + } + + protected override Task> GetChannelsInternal(TunerHostInfo tuner, CancellationToken cancellationToken) + { + throw new NotImplementedException(); + } + + public override string Type + { + get { return "SatIp"; } + } + + protected override Task> GetChannelStreamMediaSources(TunerHostInfo tuner, string channelId, CancellationToken cancellationToken) + { + throw new NotImplementedException(); + } + + protected override Task GetChannelStream(TunerHostInfo tuner, string channelId, string streamId, CancellationToken cancellationToken) + { + throw new NotImplementedException(); + } + + protected override Task IsAvailableInternal(TunerHostInfo tuner, string channelId, CancellationToken cancellationToken) + { + throw new NotImplementedException(); + } + + protected override bool IsValidChannelId(string channelId) + { + throw new NotImplementedException(); + } + } +} diff --git a/MediaBrowser.Server.Implementations/Localization/Core/ca.json b/MediaBrowser.Server.Implementations/Localization/Core/ca.json index 98039b994d..40dfcd2c38 100644 --- a/MediaBrowser.Server.Implementations/Localization/Core/ca.json +++ b/MediaBrowser.Server.Implementations/Localization/Core/ca.json @@ -71,7 +71,7 @@ "ViewTypeTvShowSeries": "S\u00e8ries:", "ViewTypeTvGenres": "G\u00e8neres", "ViewTypeTvFavoriteSeries": "S\u00e8ries Preferides", - "ViewTypeTvFavoriteEpisodes": "Episodis preferits", + "ViewTypeTvFavoriteEpisodes": "Episodis Preferits", "ViewTypeMovieResume": "Resume", "ViewTypeMovieLatest": "Darrers", "ViewTypeMovieMovies": "Pel\u00b7l\u00edcules", @@ -173,5 +173,5 @@ "HeaderWriter": "Escriptors", "HeaderParentalRatings": "Parental Ratings", "HeaderCommunityRatings": "Qualificacions de la comunitat", - "StartupEmbyServerIsLoading": "El servidor d'Emby s'est\u00e0 carregant. Si us plau, torneu-ho a provar de nou en breu." + "StartupEmbyServerIsLoading": "El servidor d'Emby s'està carregant. Si et plau, tornau-ho a provar de nou en breu." } \ No newline at end of file diff --git a/MediaBrowser.Server.Implementations/MediaBrowser.Server.Implementations.csproj b/MediaBrowser.Server.Implementations/MediaBrowser.Server.Implementations.csproj index e52c91628e..e5c94a01b4 100644 --- a/MediaBrowser.Server.Implementations/MediaBrowser.Server.Implementations.csproj +++ b/MediaBrowser.Server.Implementations/MediaBrowser.Server.Implementations.csproj @@ -43,7 +43,7 @@ False - ..\packages\CommonIO.1.0.0.5\lib\net45\CommonIO.dll + ..\packages\CommonIO.1.0.0.7\lib\net45\CommonIO.dll ..\packages\Interfaces.IO.1.0.0.5\lib\portable-net45+sl4+wp71+win8+wpa81\Interfaces.IO.dll @@ -52,15 +52,18 @@ False ..\packages\MediaBrowser.Naming.1.0.0.41\lib\portable-net45+sl4+wp71+win8+wpa81\MediaBrowser.Naming.dll + + ..\packages\morelinq.1.4.0\lib\net35\MoreLinq.dll + ..\packages\Patterns.Logging.1.0.0.2\lib\portable-net45+sl4+wp71+win8+wpa81\Patterns.Logging.dll ..\ThirdParty\ServiceStack\ServiceStack.Api.Swagger.dll - + False - ..\packages\SocketHttpListener.1.0.0.10\lib\net45\SocketHttpListener.dll + ..\packages\SocketHttpListener.1.0.0.25\lib\net45\SocketHttpListener.dll @@ -70,6 +73,7 @@ + @@ -94,9 +98,6 @@ ..\packages\Mono.Nat.1.2.24.0\lib\net40\Mono.Nat.dll - - ..\packages\morelinq.1.1.1\lib\net35\MoreLinq.dll - @@ -160,6 +161,7 @@ + @@ -216,9 +218,6 @@ - - - diff --git a/MediaBrowser.Server.Implementations/ScheduledTasks/PluginUpdateTask.cs b/MediaBrowser.Server.Implementations/ScheduledTasks/PluginUpdateTask.cs index 96f469f696..457f5a33d3 100644 --- a/MediaBrowser.Server.Implementations/ScheduledTasks/PluginUpdateTask.cs +++ b/MediaBrowser.Server.Implementations/ScheduledTasks/PluginUpdateTask.cs @@ -72,7 +72,7 @@ namespace MediaBrowser.Server.Implementations.ScheduledTasks try { - await _installationManager.InstallPackage(i, new Progress(), cancellationToken).ConfigureAwait(false); + await _installationManager.InstallPackage(i, true, new Progress(), cancellationToken).ConfigureAwait(false); } catch (OperationCanceledException) { diff --git a/MediaBrowser.Server.Implementations/packages.config b/MediaBrowser.Server.Implementations/packages.config index 7d9453822e..5c04f27826 100644 --- a/MediaBrowser.Server.Implementations/packages.config +++ b/MediaBrowser.Server.Implementations/packages.config @@ -1,10 +1,10 @@  - + - + - + \ No newline at end of file diff --git a/MediaBrowser.Server.Mono/MediaBrowser.Server.Mono.csproj b/MediaBrowser.Server.Mono/MediaBrowser.Server.Mono.csproj index e9f631bf39..9f36599fa1 100644 --- a/MediaBrowser.Server.Mono/MediaBrowser.Server.Mono.csproj +++ b/MediaBrowser.Server.Mono/MediaBrowser.Server.Mono.csproj @@ -54,7 +54,7 @@ False - ..\packages\CommonIO.1.0.0.5\lib\net45\CommonIO.dll + ..\packages\CommonIO.1.0.0.7\lib\net45\CommonIO.dll False diff --git a/MediaBrowser.Server.Mono/Program.cs b/MediaBrowser.Server.Mono/Program.cs index 69c8201af4..bccf6487a2 100644 --- a/MediaBrowser.Server.Mono/Program.cs +++ b/MediaBrowser.Server.Mono/Program.cs @@ -82,7 +82,7 @@ namespace MediaBrowser.Server.Mono var nativeApp = new NativeApp(options); - _appHost = new ApplicationHost(appPaths, logManager, options, fileSystem, "MBServer.Mono", nativeApp); + _appHost = new ApplicationHost(appPaths, logManager, options, fileSystem, "emby.mono.zip", nativeApp); if (options.ContainsOption("-v")) { diff --git a/MediaBrowser.Server.Mono/packages.config b/MediaBrowser.Server.Mono/packages.config index 6a2a6c1e5e..2956d69c6b 100644 --- a/MediaBrowser.Server.Mono/packages.config +++ b/MediaBrowser.Server.Mono/packages.config @@ -1,6 +1,6 @@  - + \ No newline at end of file diff --git a/MediaBrowser.Server.Startup.Common/ApplicationHost.cs b/MediaBrowser.Server.Startup.Common/ApplicationHost.cs index 99a7f0a152..21731a3a60 100644 --- a/MediaBrowser.Server.Startup.Common/ApplicationHost.cs +++ b/MediaBrowser.Server.Startup.Common/ApplicationHost.cs @@ -91,14 +91,17 @@ using MediaBrowser.Server.Startup.Common.Migrations; using MediaBrowser.WebDashboard.Api; using MediaBrowser.XbmcMetadata.Providers; using System; +using System.Collections.Concurrent; using System.Collections.Generic; using System.Globalization; using System.IO; using System.Linq; +using System.Net; using System.Reflection; using System.Threading; using System.Threading.Tasks; using CommonIO; +using MediaBrowser.Common.Implementations.Updates; namespace MediaBrowser.Server.Startup.Common { @@ -204,9 +207,10 @@ namespace MediaBrowser.Server.Startup.Common private IPlaylistManager PlaylistManager { get; set; } private readonly StartupOptions _startupOptions; - private readonly string _remotePackageName; + private readonly string _releaseAssetFilename; internal INativeApp NativeApp { get; set; } + private Timer _ipAddressCacheTimer; /// /// Initializes a new instance of the class. @@ -215,21 +219,23 @@ namespace MediaBrowser.Server.Startup.Common /// The log manager. /// The options. /// The file system. - /// Name of the remote package. + /// The release asset filename. /// The native application. public ApplicationHost(ServerApplicationPaths applicationPaths, ILogManager logManager, StartupOptions options, IFileSystem fileSystem, - string remotePackageName, + string releaseAssetFilename, INativeApp nativeApp) : base(applicationPaths, logManager, fileSystem) { _startupOptions = options; - _remotePackageName = remotePackageName; + _releaseAssetFilename = releaseAssetFilename; NativeApp = nativeApp; SetBaseExceptionMessage(); + + _ipAddressCacheTimer = new Timer(OnCacheClearTimerFired, null, TimeSpan.FromMinutes(3), TimeSpan.FromMinutes(3)); } private Version _version; @@ -316,6 +322,7 @@ namespace MediaBrowser.Server.Startup.Common { await base.RunStartupTasks().ConfigureAwait(false); + Logger.Info("ServerId: {0}", SystemId); Logger.Info("Core startup complete"); HttpServer.GlobalResponse = null; @@ -436,7 +443,7 @@ namespace MediaBrowser.Server.Startup.Common RegisterSingleInstance(() => new SearchEngine(LogManager, LibraryManager, UserManager)); - HttpServer = ServerFactory.CreateServer(this, LogManager, ServerConfigurationManager, "Emby", "web/index.html"); + HttpServer = ServerFactory.CreateServer(this, LogManager, ServerConfigurationManager, NetworkManager, "Emby", "web/index.html"); HttpServer.GlobalResponse = LocalizationManager.GetLocalizedString("StartupEmbyServerIsLoading"); RegisterSingleInstance(HttpServer, false); progress.Report(10); @@ -515,7 +522,7 @@ namespace MediaBrowser.Server.Startup.Common SubtitleManager = new SubtitleManager(LogManager.GetLogger("SubtitleManager"), FileSystemManager, LibraryMonitor, LibraryManager, MediaSourceManager); RegisterSingleInstance(SubtitleManager); - RegisterSingleInstance(new DeviceDiscovery(LogManager.GetLogger("IDeviceDiscovery"), ServerConfigurationManager, this)); + RegisterSingleInstance(new DeviceDiscovery(LogManager.GetLogger("IDeviceDiscovery"), ServerConfigurationManager, this, NetworkManager)); ChapterManager = new ChapterManager(LibraryManager, LogManager.GetLogger("ChapterManager"), ServerConfigurationManager, ItemRepository); RegisterSingleInstance(ChapterManager); @@ -963,6 +970,10 @@ namespace MediaBrowser.Server.Startup.Common { get { + if (!ServerConfigurationManager.Configuration.EnableAutoUpdate) + { + return false; + } #if DEBUG return false; #endif @@ -1108,14 +1119,14 @@ namespace MediaBrowser.Server.Startup.Common try { // Return the first matched address, if found, or the first known local address - var address = LocalIpAddress; + var address = LocalIpAddresses.FirstOrDefault(i => !IPAddress.IsLoopback(i)); - if (!string.IsNullOrWhiteSpace(address)) + if (address != null) { - address = GetLocalApiUrl(address); + return GetLocalApiUrl(address.ToString()); } - return address; + return null; } catch (Exception ex) { @@ -1133,40 +1144,71 @@ namespace MediaBrowser.Server.Startup.Common HttpPort.ToString(CultureInfo.InvariantCulture)); } - public string LocalIpAddress - { - get - { - return HttpServerIpAddresses.FirstOrDefault(); - } - } - - private IEnumerable HttpServerIpAddresses + public List LocalIpAddresses { get { var localAddresses = NetworkManager.GetLocalIpAddresses() + .Where(IsIpAddressValid) .ToList(); - var httpServerAddresses = HttpServer.LocalEndPoints - .Select(i => i.Split(':').FirstOrDefault()) - .Where(i => !string.IsNullOrEmpty(i)) - .ToList(); - - // Cross-check the local ip addresses with addresses that have been received on with the http server - var matchedAddresses = httpServerAddresses - .Where(i => localAddresses.Contains(i, StringComparer.OrdinalIgnoreCase)) - .ToList(); - - if (matchedAddresses.Count == 0) - { - return localAddresses; - } - - return matchedAddresses; + return localAddresses; } } + private readonly ConcurrentDictionary _validAddressResults = new ConcurrentDictionary(StringComparer.OrdinalIgnoreCase); + private bool IsIpAddressValid(IPAddress address) + { + if (IPAddress.IsLoopback(address)) + { + return true; + } + + var apiUrl = GetLocalApiUrl(address.ToString()); + apiUrl += "/system/ping"; + + bool cachedResult; + if (_validAddressResults.TryGetValue(apiUrl, out cachedResult)) + { + return cachedResult; + } + + try + { + using (var response = HttpClient.SendAsync(new HttpRequestOptions + { + Url = apiUrl, + LogErrorResponseBody = false, + LogErrors = false, + LogRequest = false + + }, "POST").Result) + { + using (var reader = new StreamReader(response.Content)) + { + var result = reader.ReadToEnd(); + var valid = string.Equals(Name, result, StringComparison.OrdinalIgnoreCase); + + _validAddressResults.AddOrUpdate(apiUrl, valid, (k, v) => valid); + Logger.Debug("Ping test result to {0}. Success: {1}", apiUrl, valid); + return valid; + } + } + } + catch + { + Logger.Debug("Ping test result to {0}. Success: {1}", apiUrl, false); + + _validAddressResults.AddOrUpdate(apiUrl, false, (k, v) => false); + return false; + } + } + + private void OnCacheClearTimerFired(object state) + { + _validAddressResults.Clear(); + } + public string FriendlyName { get @@ -1263,25 +1305,23 @@ namespace MediaBrowser.Server.Startup.Common /// Task{CheckForUpdateResult}. public override async Task CheckForApplicationUpdate(CancellationToken cancellationToken, IProgress progress) { - var availablePackages = await InstallationManager.GetAvailablePackagesWithoutRegistrationInfo(cancellationToken).ConfigureAwait(false); + var cacheLength = TimeSpan.FromHours(3); + var updateLevel = ConfigurationManager.CommonConfiguration.SystemUpdateLevel; - var version = InstallationManager.GetLatestCompatibleVersion(availablePackages, _remotePackageName, null, ApplicationVersion, ConfigurationManager.CommonConfiguration.SystemUpdateLevel); + if (updateLevel == PackageVersionClass.Beta) + { + cacheLength = TimeSpan.FromHours(1); + } + else if (updateLevel == PackageVersionClass.Dev) + { + cacheLength = TimeSpan.FromMinutes(5); + } - var versionObject = version == null || string.IsNullOrWhiteSpace(version.versionStr) ? null : new Version(version.versionStr); - - var isUpdateAvailable = versionObject != null && versionObject > ApplicationVersion; - - var result = versionObject != null ? - new CheckForUpdateResult { AvailableVersion = versionObject.ToString(), IsUpdateAvailable = isUpdateAvailable, Package = version } : - new CheckForUpdateResult { AvailableVersion = ApplicationVersion.ToString(), IsUpdateAvailable = false }; + var result = await new GithubUpdater(HttpClient, JsonSerializer, cacheLength).CheckForUpdateResult("MediaBrowser", "Emby", ApplicationVersion, updateLevel, _releaseAssetFilename, + "MBServer", "Mbserver.zip", cancellationToken).ConfigureAwait(false); HasUpdateAvailable = result.IsUpdateAvailable; - if (result.IsUpdateAvailable) - { - Logger.Info("New application version is available: {0}", result.AvailableVersion); - } - return result; } @@ -1294,7 +1334,7 @@ namespace MediaBrowser.Server.Startup.Common /// Task. public override async Task UpdateApplication(PackageVersionInfo package, CancellationToken cancellationToken, IProgress progress) { - await InstallationManager.InstallPackage(package, progress, cancellationToken).ConfigureAwait(false); + await InstallationManager.InstallPackage(package, false, progress, cancellationToken).ConfigureAwait(false); HasUpdateAvailable = false; diff --git a/MediaBrowser.Server.Startup.Common/MediaBrowser.Server.Startup.Common.csproj b/MediaBrowser.Server.Startup.Common/MediaBrowser.Server.Startup.Common.csproj index 13b782e406..6dd2066bbc 100644 --- a/MediaBrowser.Server.Startup.Common/MediaBrowser.Server.Startup.Common.csproj +++ b/MediaBrowser.Server.Startup.Common/MediaBrowser.Server.Startup.Common.csproj @@ -33,7 +33,7 @@ False - ..\packages\CommonIO.1.0.0.5\lib\net45\CommonIO.dll + ..\packages\CommonIO.1.0.0.7\lib\net45\CommonIO.dll False diff --git a/MediaBrowser.Server.Startup.Common/packages.config b/MediaBrowser.Server.Startup.Common/packages.config index 6a2a6c1e5e..2956d69c6b 100644 --- a/MediaBrowser.Server.Startup.Common/packages.config +++ b/MediaBrowser.Server.Startup.Common/packages.config @@ -1,6 +1,6 @@  - + \ No newline at end of file diff --git a/MediaBrowser.ServerApplication/MainStartup.cs b/MediaBrowser.ServerApplication/MainStartup.cs index b8af35fde1..62cdbd05f4 100644 --- a/MediaBrowser.ServerApplication/MainStartup.cs +++ b/MediaBrowser.ServerApplication/MainStartup.cs @@ -18,6 +18,9 @@ using System.Threading; using System.Threading.Tasks; using System.Windows.Forms; using CommonIO.Windows; +using Emby.Drawing.ImageMagick; +using ImageMagickSharp; +using MediaBrowser.Common.Net; using MediaBrowser.Server.Implementations.Logging; namespace MediaBrowser.ServerApplication @@ -29,6 +32,10 @@ namespace MediaBrowser.ServerApplication private static ILogger _logger; private static bool _isRunningAsService = false; + private static bool _appHostDisposed; + + [DllImport("kernel32.dll", SetLastError = true)] + static extern bool SetDllDirectory(string lpPathName); /// /// Defines the entry point of the application. @@ -41,6 +48,11 @@ namespace MediaBrowser.ServerApplication var currentProcess = Process.GetCurrentProcess(); var applicationPath = currentProcess.MainModule.FileName; + var architecturePath = Path.Combine(Path.GetDirectoryName(applicationPath), Environment.Is64BitProcess ? "x64" : "x86"); + + Wand.SetMagickCoderModulePath(architecturePath); + + var success = SetDllDirectory(architecturePath); var appPaths = CreateApplicationPaths(applicationPath, _isRunningAsService); @@ -136,7 +148,7 @@ namespace MediaBrowser.ServerApplication { _logger.Info("Found a duplicate process. Giving it time to exit."); - if (!duplicate.WaitForExit(10000)) + if (!duplicate.WaitForExit(12000)) { _logger.Info("The duplicate process did not exit."); return true; @@ -215,7 +227,7 @@ namespace MediaBrowser.ServerApplication logManager, options, fileSystem, - "MBServer", + "emby.windows.zip", nativeApp); var initProgress = new Progress(); @@ -241,6 +253,9 @@ namespace MediaBrowser.ServerApplication { Task.WaitAll(task); + task = InstallVcredistIfNeeded(_appHost, _logger); + Task.WaitAll(task); + SystemEvents.SessionEnding += SystemEvents_SessionEnding; SystemEvents.SessionSwitch += SystemEvents_SessionSwitch; @@ -329,7 +344,7 @@ namespace MediaBrowser.ServerApplication { _logger.Info("Shutting down"); - _appHost.Dispose(); + DisposeAppHost(); } /// @@ -500,14 +515,15 @@ namespace MediaBrowser.ServerApplication } else { + DisposeAppHost(); + ShutdownWindowsApplication(); } } public static void Restart() { - _logger.Info("Disposing app host"); - _appHost.Dispose(); + DisposeAppHost(); if (!_isRunningAsService) { @@ -522,11 +538,24 @@ namespace MediaBrowser.ServerApplication } } + private static void DisposeAppHost() + { + if (!_appHostDisposed) + { + _logger.Info("Disposing app host"); + + _appHostDisposed = true; + _appHost.Dispose(); + } + } + private static void ShutdownWindowsApplication() { _logger.Info("Calling Application.Exit"); Application.Exit(); + Environment.Exit(0); + _logger.Info("Calling ApplicationTaskCompletionSource.SetResult"); ApplicationTaskCompletionSource.SetResult(true); } @@ -544,6 +573,72 @@ namespace MediaBrowser.ServerApplication } } + private static async Task InstallVcredistIfNeeded(ApplicationHost appHost, ILogger logger) + { + try + { + var version = ImageMagickEncoder.GetVersion(); + return; + } + catch (Exception ex) + { + logger.ErrorException("Error loading ImageMagick", ex); + } + + try + { + await InstallVcredist().ConfigureAwait(false); + } + catch (Exception ex) + { + logger.ErrorException("Error installing Visual Studio C++ runtime", ex); + } + } + + private async static Task InstallVcredist() + { + var httpClient = _appHost.HttpClient; + + var tmp = await httpClient.GetTempFile(new HttpRequestOptions + { + Url = GetVcredistUrl(), + Progress = new Progress() + + }).ConfigureAwait(false); + + var exePath = Path.ChangeExtension(tmp, ".exe"); + File.Copy(tmp, exePath); + + var startInfo = new ProcessStartInfo + { + FileName = exePath, + + CreateNoWindow = true, + WindowStyle = ProcessWindowStyle.Hidden, + Verb = "runas", + ErrorDialog = false + }; + + _logger.Info("Running {0}", startInfo.FileName); + + using (var process = Process.Start(startInfo)) + { + process.WaitForExit(); + } + } + + private static string GetVcredistUrl() + { + if (Environment.Is64BitProcess) + { + return "https://github.com/MediaBrowser/Emby.Resources/raw/master/vcredist2013/vcredist_x64.exe"; + } + + // TODO: ARM url - https://github.com/MediaBrowser/Emby.Resources/raw/master/vcredist2013/vcredist_arm.exe + + return "https://github.com/MediaBrowser/Emby.Resources/raw/master/vcredist2013/vcredist_x86.exe"; + } + /// /// Sets the error mode. /// diff --git a/MediaBrowser.ServerApplication/MediaBrowser.ServerApplication.csproj b/MediaBrowser.ServerApplication/MediaBrowser.ServerApplication.csproj index 5813dcac58..3e62f47351 100644 --- a/MediaBrowser.ServerApplication/MediaBrowser.ServerApplication.csproj +++ b/MediaBrowser.ServerApplication/MediaBrowser.ServerApplication.csproj @@ -22,7 +22,7 @@ DEBUG;TRACE prompt 4 - true + false AnyCPU @@ -32,6 +32,7 @@ TRACE prompt 4 + false MediaBrowser.ServerApplication.MainStartup @@ -62,10 +63,11 @@ False - ..\packages\CommonIO.1.0.0.5\lib\net45\CommonIO.dll + ..\packages\CommonIO.1.0.0.7\lib\net45\CommonIO.dll - - ..\packages\ImageMagickSharp.1.0.0.16\lib\net45\ImageMagickSharp.dll + + False + ..\packages\ImageMagickSharp.1.0.0.17\lib\net45\ImageMagickSharp.dll ..\packages\MediaBrowser.IsoMounting.3.0.69\lib\net45\MediaBrowser.IsoMounter.dll @@ -156,18 +158,6 @@ - - MediaBrowser.InstallUtil.dll - PreserveNewest - - - MediaBrowser.Uninstaller.exe - PreserveNewest - - - MediaBrowser.Updater.exe - PreserveNewest - x64\SQLite.Interop.dll PreserveNewest @@ -176,235 +166,899 @@ x86\SQLite.Interop.dll PreserveNewest - + + MediaBrowser.InstallUtil.dll PreserveNewest - + + MediaBrowser.Uninstaller.exe PreserveNewest - + + MediaBrowser.Updater.exe PreserveNewest - + PreserveNewest - + PreserveNewest - + PreserveNewest - + PreserveNewest - + PreserveNewest - + PreserveNewest - + PreserveNewest - + PreserveNewest - + PreserveNewest - + PreserveNewest - + PreserveNewest - + PreserveNewest - + PreserveNewest - + PreserveNewest - + PreserveNewest - + PreserveNewest - + PreserveNewest - + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + PreserveNewest - + PreserveNewest - + PreserveNewest - + PreserveNewest - + PreserveNewest - + PreserveNewest - + PreserveNewest - + PreserveNewest - + PreserveNewest - + PreserveNewest - + PreserveNewest - + PreserveNewest - + PreserveNewest - + PreserveNewest - + PreserveNewest - + PreserveNewest - + PreserveNewest - + PreserveNewest - + PreserveNewest - + PreserveNewest - + PreserveNewest - + PreserveNewest - + PreserveNewest - + PreserveNewest - + PreserveNewest - + PreserveNewest - + PreserveNewest - + PreserveNewest - + PreserveNewest - + PreserveNewest - + PreserveNewest - + PreserveNewest - + PreserveNewest - + PreserveNewest - + PreserveNewest - + PreserveNewest - + PreserveNewest - + PreserveNewest - + PreserveNewest - + PreserveNewest - + PreserveNewest - + PreserveNewest - + PreserveNewest - + PreserveNewest - + PreserveNewest - + PreserveNewest - + PreserveNewest - + PreserveNewest - + PreserveNewest - + PreserveNewest - + PreserveNewest - + PreserveNewest - + PreserveNewest - + PreserveNewest - + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + PreserveNewest + + {08fff49b-f175-4807-a2b5-73b0ebd9f716} + Emby.Drawing + {4fd51ac5-2c16-4308-a993-c3a84f3b4582} MediaBrowser.Api diff --git a/MediaBrowser.ServerApplication/Native/Autorun.cs b/MediaBrowser.ServerApplication/Native/Autorun.cs index 2cacaae8ed..c384d04602 100644 --- a/MediaBrowser.ServerApplication/Native/Autorun.cs +++ b/MediaBrowser.ServerApplication/Native/Autorun.cs @@ -17,25 +17,10 @@ namespace MediaBrowser.ServerApplication.Native /// The file system. public static void Configure(bool autorun, IFileSystem fileSystem) { - var shortcutPath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.StartMenu), "Media Browser 3", "Media Browser Server.lnk"); - - if (!Directory.Exists(Path.GetDirectoryName(shortcutPath))) - { - shortcutPath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.StartMenu), "Emby", "Emby Server.lnk"); - } + var shortcutPath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.StartMenu), "Emby", "Emby Server.lnk"); var startupPath = Environment.GetFolderPath(Environment.SpecialFolder.Startup); - // Remove lnk from old name - try - { - fileSystem.DeleteFile(Path.Combine(startupPath, Path.GetFileName(shortcutPath) ?? "Media Browser Server.lnk")); - } - catch - { - - } - if (autorun) { //Copy our shortut into the startup folder for this user diff --git a/MediaBrowser.ServerApplication/Native/WindowsApp.cs b/MediaBrowser.ServerApplication/Native/WindowsApp.cs index bff342d01f..ceab5379d5 100644 --- a/MediaBrowser.ServerApplication/Native/WindowsApp.cs +++ b/MediaBrowser.ServerApplication/Native/WindowsApp.cs @@ -24,7 +24,7 @@ namespace MediaBrowser.ServerApplication.Native if (!System.Environment.Is64BitProcess) { - list.Add(typeof(PismoIsoManager).Assembly); + //list.Add(typeof(PismoIsoManager).Assembly); } list.Add(GetType().Assembly); diff --git a/MediaBrowser.ServerApplication/ServerNotifyIcon.cs b/MediaBrowser.ServerApplication/ServerNotifyIcon.cs index e9a7d59857..673c6cdddf 100644 --- a/MediaBrowser.ServerApplication/ServerNotifyIcon.cs +++ b/MediaBrowser.ServerApplication/ServerNotifyIcon.cs @@ -133,9 +133,22 @@ namespace MediaBrowser.ServerApplication LocalizeText(); notifyIcon1.DoubleClick += notifyIcon1_DoubleClick; + Application.ThreadExit += Application_ThreadExit; Application.ApplicationExit += Application_ApplicationExit; } + void Application_ThreadExit(object sender, EventArgs e) + { + try + { + notifyIcon1.Visible = false; + } + catch + { + + } + } + void Application_ApplicationExit(object sender, EventArgs e) { try diff --git a/MediaBrowser.ServerApplication/packages.config b/MediaBrowser.ServerApplication/packages.config index dec8199cc2..db2bb54761 100644 --- a/MediaBrowser.ServerApplication/packages.config +++ b/MediaBrowser.ServerApplication/packages.config @@ -1,7 +1,7 @@  - - + + diff --git a/MediaBrowser.WebDashboard/MediaBrowser.WebDashboard.csproj b/MediaBrowser.WebDashboard/MediaBrowser.WebDashboard.csproj index 4da1f42c44..48a8bf253e 100644 --- a/MediaBrowser.WebDashboard/MediaBrowser.WebDashboard.csproj +++ b/MediaBrowser.WebDashboard/MediaBrowser.WebDashboard.csproj @@ -49,7 +49,7 @@ False - ..\packages\CommonIO.1.0.0.5\lib\net45\CommonIO.dll + ..\packages\CommonIO.1.0.0.7\lib\net45\CommonIO.dll ..\packages\Patterns.Logging.1.0.0.2\lib\portable-net45+sl4+wp71+win8+wpa81\Patterns.Logging.dll @@ -122,9 +122,6 @@ PreserveNewest - - PreserveNewest - PreserveNewest diff --git a/MediaBrowser.WebDashboard/packages.config b/MediaBrowser.WebDashboard/packages.config index 24a8a5316e..128a2f1628 100644 --- a/MediaBrowser.WebDashboard/packages.config +++ b/MediaBrowser.WebDashboard/packages.config @@ -1,6 +1,6 @@  - + diff --git a/MediaBrowser.XbmcMetadata/MediaBrowser.XbmcMetadata.csproj b/MediaBrowser.XbmcMetadata/MediaBrowser.XbmcMetadata.csproj index 353fe31caa..16b6ca9956 100644 --- a/MediaBrowser.XbmcMetadata/MediaBrowser.XbmcMetadata.csproj +++ b/MediaBrowser.XbmcMetadata/MediaBrowser.XbmcMetadata.csproj @@ -33,7 +33,7 @@ False - ..\packages\CommonIO.1.0.0.5\lib\net45\CommonIO.dll + ..\packages\CommonIO.1.0.0.7\lib\net45\CommonIO.dll ..\packages\Patterns.Logging.1.0.0.2\lib\portable-net45+sl4+wp71+win8+wpa81\Patterns.Logging.dll diff --git a/MediaBrowser.XbmcMetadata/Savers/BaseNfoSaver.cs b/MediaBrowser.XbmcMetadata/Savers/BaseNfoSaver.cs index fa58b67dae..0da53f575c 100644 --- a/MediaBrowser.XbmcMetadata/Savers/BaseNfoSaver.cs +++ b/MediaBrowser.XbmcMetadata/Savers/BaseNfoSaver.cs @@ -305,8 +305,19 @@ namespace MediaBrowser.XbmcMetadata.Savers if (!string.IsNullOrEmpty(stream.Codec)) { - writer.WriteElementString("codec", stream.Codec); - writer.WriteElementString("micodec", stream.Codec); + var codec = stream.Codec; + + if ((stream.CodecTag ?? string.Empty).IndexOf("xvid", StringComparison.OrdinalIgnoreCase) != -1) + { + codec = "xvid;"; + } + else if ((stream.CodecTag ?? string.Empty).IndexOf("divx", StringComparison.OrdinalIgnoreCase) != -1) + { + codec = "divx;"; + } + + writer.WriteElementString("codec", codec); + writer.WriteElementString("micodec", codec); } if (stream.BitRate.HasValue) diff --git a/MediaBrowser.XbmcMetadata/packages.config b/MediaBrowser.XbmcMetadata/packages.config index fad6af08eb..28556744da 100644 --- a/MediaBrowser.XbmcMetadata/packages.config +++ b/MediaBrowser.XbmcMetadata/packages.config @@ -1,5 +1,5 @@  - + \ No newline at end of file