Browse Source

Merge pull request #2333 from MediaBrowser/dev

Dev
Luke 8 years ago
parent
commit
862018b5c2

+ 5 - 2
Emby.Common.Implementations/Net/NetSocket.cs

@@ -13,7 +13,9 @@ namespace Emby.Common.Implementations.Net
         public Socket Socket { get; private set; }
         public Socket Socket { get; private set; }
         private readonly ILogger _logger;
         private readonly ILogger _logger;
 
 
-        public NetSocket(Socket socket, ILogger logger)
+        public bool DualMode { get; private set; }
+
+        public NetSocket(Socket socket, ILogger logger, bool isDualMode)
         {
         {
             if (socket == null)
             if (socket == null)
             {
             {
@@ -26,6 +28,7 @@ namespace Emby.Common.Implementations.Net
 
 
             Socket = socket;
             Socket = socket;
             _logger = logger;
             _logger = logger;
+            DualMode = isDualMode;
         }
         }
 
 
         public IpEndPointInfo LocalEndPoint
         public IpEndPointInfo LocalEndPoint
@@ -81,7 +84,7 @@ namespace Emby.Common.Implementations.Net
         private SocketAcceptor _acceptor;
         private SocketAcceptor _acceptor;
         public void StartAccept(Action<ISocket> onAccept, Func<bool> isClosed)
         public void StartAccept(Action<ISocket> onAccept, Func<bool> isClosed)
         {
         {
-            _acceptor = new SocketAcceptor(_logger, Socket, onAccept, isClosed);
+            _acceptor = new SocketAcceptor(_logger, Socket, onAccept, isClosed, DualMode);
 
 
             _acceptor.StartAccept();
             _acceptor.StartAccept();
         }
         }

+ 4 - 2
Emby.Common.Implementations/Net/SocketAcceptor.cs

@@ -11,8 +11,9 @@ namespace Emby.Common.Implementations.Net
         private readonly Socket _originalSocket;
         private readonly Socket _originalSocket;
         private readonly Func<bool> _isClosed;
         private readonly Func<bool> _isClosed;
         private readonly Action<ISocket> _onAccept;
         private readonly Action<ISocket> _onAccept;
+        private readonly bool _isDualMode;
 
 
-        public SocketAcceptor(ILogger logger, Socket originalSocket, Action<ISocket> onAccept, Func<bool> isClosed)
+        public SocketAcceptor(ILogger logger, Socket originalSocket, Action<ISocket> onAccept, Func<bool> isClosed, bool isDualMode)
         {
         {
             if (logger == null)
             if (logger == null)
             {
             {
@@ -34,6 +35,7 @@ namespace Emby.Common.Implementations.Net
             _logger = logger;
             _logger = logger;
             _originalSocket = originalSocket;
             _originalSocket = originalSocket;
             _isClosed = isClosed;
             _isClosed = isClosed;
+            _isDualMode = isDualMode;
             _onAccept = onAccept;
             _onAccept = onAccept;
         }
         }
 
 
@@ -115,7 +117,7 @@ namespace Emby.Common.Implementations.Net
             if (acceptSocket != null)
             if (acceptSocket != null)
             {
             {
                 //ProcessAccept(acceptSocket);
                 //ProcessAccept(acceptSocket);
-                _onAccept(new NetSocket(acceptSocket, _logger));
+                _onAccept(new NetSocket(acceptSocket, _logger, _isDualMode));
             }
             }
 
 
             // Accept the next connection request
             // Accept the next connection request

+ 2 - 12
Emby.Common.Implementations/Net/SocketFactory.cs

@@ -46,21 +46,11 @@ namespace Emby.Common.Implementations.Net
                     socket.DualMode = true;
                     socket.DualMode = true;
                 }
                 }
 
 
-                return new NetSocket(socket, _logger);
+                return new NetSocket(socket, _logger, dualMode);
             }
             }
             catch (SocketException ex)
             catch (SocketException ex)
             {
             {
-                if (dualMode)
-                {
-                    _logger.Error("Error creating dual mode socket: {0}. Will retry with ipv4-only.", ex.SocketErrorCode);
-
-                    if (ex.SocketErrorCode == SocketError.AddressFamilyNotSupported)
-                    {
-                        return CreateSocket(IpAddressFamily.InterNetwork, socketType, protocolType, false);
-                    }
-                }
-
-                throw;
+                throw new SocketCreateException(ex.SocketErrorCode.ToString(), ex);
             }
             }
         }
         }
 
 

+ 39 - 8
Emby.Server.Core/ApplicationHost.cs

@@ -1305,19 +1305,49 @@ namespace Emby.Server.Core
 
 
         public async Task<List<IpAddressInfo>> GetLocalIpAddresses()
         public async Task<List<IpAddressInfo>> GetLocalIpAddresses()
         {
         {
-            var addresses = NetworkManager.GetLocalIpAddresses().ToList();
-            var list = new List<IpAddressInfo>();
+            var addresses = ServerConfigurationManager
+                .Configuration
+                .LocalNetworkAddresses
+                .Select(NormalizeConfiguredLocalAddress)
+                .Where(i => i != null)
+                .ToList();
 
 
-            foreach (var address in addresses)
+            if (addresses.Count == 0)
             {
             {
-                var valid = await IsIpAddressValidAsync(address).ConfigureAwait(false);
-                if (valid)
+                addresses.AddRange(NetworkManager.GetLocalIpAddresses());
+
+                var list = new List<IpAddressInfo>();
+
+                foreach (var address in addresses)
                 {
                 {
-                    list.Add(address);
+                    var valid = await IsIpAddressValidAsync(address).ConfigureAwait(false);
+                    if (valid)
+                    {
+                        list.Add(address);
+                    }
                 }
                 }
+
+                addresses = list;
             }
             }
 
 
-            return list;
+            return addresses;
+        }
+
+        private IpAddressInfo NormalizeConfiguredLocalAddress(string address)
+        {
+            var index = address.Trim('/').IndexOf('/');
+
+            if (index != -1)
+            {
+                address = address.Substring(index + 1);
+            }
+
+            IpAddressInfo result;
+            if (NetworkManager.TryParseIpAddress(address.Trim('/'), out result))
+            {
+                return result;
+            }
+            return null;
         }
         }
 
 
         private readonly ConcurrentDictionary<string, bool> _validAddressResults = new ConcurrentDictionary<string, bool>(StringComparer.OrdinalIgnoreCase);
         private readonly ConcurrentDictionary<string, bool> _validAddressResults = new ConcurrentDictionary<string, bool>(StringComparer.OrdinalIgnoreCase);
@@ -1553,7 +1583,8 @@ namespace Emby.Server.Core
                 throw new NotImplementedException();
                 throw new NotImplementedException();
             }
             }
 
 
-            var process = ProcessFactory.Create(new ProcessOptions {
+            var process = ProcessFactory.Create(new ProcessOptions
+            {
                 FileName = url,
                 FileName = url,
                 EnableRaisingEvents = true,
                 EnableRaisingEvents = true,
                 UseShellExecute = true,
                 UseShellExecute = true,

+ 21 - 0
Emby.Server.Implementations/Dto/DtoService.cs

@@ -1351,6 +1351,27 @@ namespace Emby.Server.Implementations.Dto
                     if (episodeSeries != null)
                     if (episodeSeries != null)
                     {
                     {
                         dto.SeriesStudio = episodeSeries.Studios.FirstOrDefault();
                         dto.SeriesStudio = episodeSeries.Studios.FirstOrDefault();
+                        if (!string.IsNullOrWhiteSpace(dto.SeriesStudio))
+                        {
+                            try
+                            {
+                                var studio = _libraryManager.GetStudio(dto.SeriesStudio);
+
+                                if (studio != null)
+                                {
+                                    dto.SeriesStudioInfo = new StudioDto
+                                    {
+                                        Name = dto.SeriesStudio,
+                                        Id = studio.Id.ToString("N"),
+                                        PrimaryImageTag = GetImageCacheTag(studio, ImageType.Primary)
+                                    };
+                                }
+                            }
+                            catch (Exception ex)
+                            {
+                                
+                            }
+                        }
                     }
                     }
                 }
                 }
             }
             }

+ 2 - 2
Emby.Server.Implementations/Library/LibraryManager.cs

@@ -341,13 +341,13 @@ namespace Emby.Server.Implementations.Library
             }
             }
             if (item is IItemByName)
             if (item is IItemByName)
             {
             {
-                if (!(item is MusicArtist))
+                if (!(item is MusicArtist) && !(item is Studio))
                 {
                 {
                     return;
                     return;
                 }
                 }
             }
             }
 
 
-            if (item.IsFolder)
+            else if (item.IsFolder)
             {
             {
                 //if (!(item is ICollectionFolder) && !(item is UserView) && !(item is Channel) && !(item is AggregateFolder))
                 //if (!(item is ICollectionFolder) && !(item is UserView) && !(item is Channel) && !(item is AggregateFolder))
                 //{
                 //{

+ 11 - 1
Emby.Server.Implementations/LiveTv/EmbyTV/EmbyTV.cs

@@ -1594,7 +1594,17 @@ namespace Emby.Server.Implementations.LiveTv.EmbyTV
 
 
         private void Process_Exited(object sender, EventArgs e)
         private void Process_Exited(object sender, EventArgs e)
         {
         {
-            ((IProcess)sender).Dispose();
+            var process = (IProcess)sender;
+            try
+            {
+                _logger.Info("Recording post-processing script completed with exit code {0}", process.ExitCode);
+            }
+            catch
+            {
+
+            }
+
+            process.Dispose();
         }
         }
 
 
         private async Task SaveRecordingImage(string recordingPath, LiveTvProgram program, ItemImageInfo image)
         private async Task SaveRecordingImage(string recordingPath, LiveTvProgram program, ItemImageInfo image)

+ 14 - 7
Emby.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunHost.cs

@@ -377,7 +377,9 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts.HdHomerun
 
 
             var url = GetApiUrl(info, true) + "/auto/v" + channelId;
             var url = GetApiUrl(info, true) + "/auto/v" + channelId;
 
 
-            if (!string.IsNullOrWhiteSpace(profile) && !string.Equals(profile, "native", StringComparison.OrdinalIgnoreCase))
+            // If raw was used, the tuner doesn't support params
+            if (!string.IsNullOrWhiteSpace(profile)
+                && !string.Equals(profile, "native", StringComparison.OrdinalIgnoreCase))
             {
             {
                 url += "?transcode=" + profile;
                 url += "?transcode=" + profile;
             }
             }
@@ -451,16 +453,16 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts.HdHomerun
             }
             }
             var hdhrId = GetHdHrIdFromChannelId(channelId);
             var hdhrId = GetHdHrIdFromChannelId(channelId);
 
 
-            list.Add(await GetMediaSource(info, hdhrId, "native").ConfigureAwait(false));
-
             try
             try
             {
             {
-                if (info.AllowHWTranscoding)
+                var model = await GetModelInfo(info, cancellationToken).ConfigureAwait(false);
+                model = model ?? string.Empty;
+
+                if ((model.IndexOf("hdtc", StringComparison.OrdinalIgnoreCase) != -1))
                 {
                 {
-                    string model = await GetModelInfo(info, cancellationToken).ConfigureAwait(false);
-                    model = model ?? string.Empty;
+                    list.Add(await GetMediaSource(info, hdhrId, "native").ConfigureAwait(false));
 
 
-                    if ((model.IndexOf("hdtc", StringComparison.OrdinalIgnoreCase) != -1))
+                    if (info.AllowHWTranscoding)
                     {
                     {
                         list.Add(await GetMediaSource(info, hdhrId, "heavy").ConfigureAwait(false));
                         list.Add(await GetMediaSource(info, hdhrId, "heavy").ConfigureAwait(false));
 
 
@@ -477,6 +479,11 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts.HdHomerun
 
 
             }
             }
 
 
+            if (list.Count == 0)
+            {
+                list.Add(await GetMediaSource(info, hdhrId, "native").ConfigureAwait(false));
+            }
+
             return list;
             return list;
         }
         }
 
 

+ 65 - 17
Emby.Server.Implementations/LiveTv/TunerHosts/M3uParser.cs

@@ -1,5 +1,6 @@
 using System;
 using System;
 using System.Collections.Generic;
 using System.Collections.Generic;
+using System.Globalization;
 using System.IO;
 using System.IO;
 using System.Linq;
 using System.Linq;
 using System.Text.RegularExpressions;
 using System.Text.RegularExpressions;
@@ -100,16 +101,23 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts
 
 
             extInf = extInf.Trim();
             extInf = extInf.Trim();
 
 
-            channel.ImageUrl = FindProperty("tvg-logo", extInf);
+            string remaining;
+            var attributes = ParseExtInf(extInf, out remaining);
+            extInf = remaining;
 
 
-            channel.Name = GetChannelName(extInf);
+            string value;
+            if (attributes.TryGetValue("tvg-logo", out value))
+            {
+                channel.ImageUrl = value;
+            }
 
 
-            channel.Number = GetChannelNumber(extInf, mediaUrl);
+            channel.Name = GetChannelName(extInf, attributes);
+            channel.Number = GetChannelNumber(extInf, attributes, mediaUrl);
 
 
             return channel;
             return channel;
         }
         }
 
 
-        private string GetChannelNumber(string extInf, string mediaUrl)
+        private string GetChannelNumber(string extInf, Dictionary<string, string> attributes, string mediaUrl)
         {
         {
             var nameParts = extInf.Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries);
             var nameParts = extInf.Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries);
             var nameInExtInf = nameParts.Length > 1 ? nameParts.Last().Trim() : null;
             var nameInExtInf = nameParts.Length > 1 ? nameParts.Last().Trim() : null;
@@ -130,18 +138,41 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts
                 }
                 }
             }
             }
 
 
-            if (string.IsNullOrWhiteSpace(numberString) || 
+            if (!string.IsNullOrWhiteSpace(numberString))
+            {
+                numberString = numberString.Trim();
+            }
+
+            if (string.IsNullOrWhiteSpace(numberString) ||
                 string.Equals(numberString, "-1", StringComparison.OrdinalIgnoreCase) ||
                 string.Equals(numberString, "-1", StringComparison.OrdinalIgnoreCase) ||
                 string.Equals(numberString, "0", StringComparison.OrdinalIgnoreCase))
                 string.Equals(numberString, "0", StringComparison.OrdinalIgnoreCase))
             {
             {
-                numberString = FindProperty("tvg-id", extInf);
+                string value;
+                if (attributes.TryGetValue("tvg-id", out value))
+                {
+                    numberString = value;
+                }
+            }
+
+            if (!string.IsNullOrWhiteSpace(numberString))
+            {
+                numberString = numberString.Trim();
             }
             }
 
 
             if (string.IsNullOrWhiteSpace(numberString) ||
             if (string.IsNullOrWhiteSpace(numberString) ||
                 string.Equals(numberString, "-1", StringComparison.OrdinalIgnoreCase) ||
                 string.Equals(numberString, "-1", StringComparison.OrdinalIgnoreCase) ||
                 string.Equals(numberString, "0", StringComparison.OrdinalIgnoreCase))
                 string.Equals(numberString, "0", StringComparison.OrdinalIgnoreCase))
             {
             {
-                numberString = FindProperty("channel-id", extInf);
+                string value;
+                if (attributes.TryGetValue("channel-id", out value))
+                {
+                    numberString = value;
+                }
+            }
+
+            if (!string.IsNullOrWhiteSpace(numberString))
+            {
+                numberString = numberString.Trim();
             }
             }
 
 
             if (string.IsNullOrWhiteSpace(numberString) ||
             if (string.IsNullOrWhiteSpace(numberString) ||
@@ -160,13 +191,19 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts
                 else
                 else
                 {
                 {
                     numberString = Path.GetFileNameWithoutExtension(mediaUrl.Split('/').Last());
                     numberString = Path.GetFileNameWithoutExtension(mediaUrl.Split('/').Last());
+
+                    double value;
+                    if (!double.TryParse(numberString, NumberStyles.Any, CultureInfo.InvariantCulture, out value))
+                    {
+                        numberString = null;
+                    }
                 }
                 }
             }
             }
 
 
             return numberString;
             return numberString;
         }
         }
 
 
-        private string GetChannelName(string extInf)
+        private string GetChannelName(string extInf, Dictionary<string, string> attributes)
         {
         {
             var nameParts = extInf.Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries);
             var nameParts = extInf.Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries);
             var nameInExtInf = nameParts.Length > 1 ? nameParts.Last().Trim() : null;
             var nameInExtInf = nameParts.Length > 1 ? nameParts.Last().Trim() : null;
@@ -186,7 +223,9 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts
                 }
                 }
             }
             }
 
 
-            var name = FindProperty("tvg-name", extInf);
+            string name;
+            attributes.TryGetValue("tvg-name", out name);
+
             if (string.IsNullOrWhiteSpace(name))
             if (string.IsNullOrWhiteSpace(name))
             {
             {
                 name = nameInExtInf;
                 name = nameInExtInf;
@@ -194,7 +233,7 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts
 
 
             if (string.IsNullOrWhiteSpace(name))
             if (string.IsNullOrWhiteSpace(name))
             {
             {
-                name = FindProperty("tvg-id", extInf);
+                attributes.TryGetValue("tvg-id", out name);
             }
             }
 
 
             if (string.IsNullOrWhiteSpace(name))
             if (string.IsNullOrWhiteSpace(name))
@@ -205,18 +244,27 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts
             return name;
             return name;
         }
         }
 
 
-        private string FindProperty(string property, string properties)
+        private Dictionary<string, string> ParseExtInf(string line, out string remaining)
         {
         {
+            var dict = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);
+
             var reg = new Regex(@"([a-z0-9\-_]+)=\""([^""]+)\""", RegexOptions.IgnoreCase);
             var reg = new Regex(@"([a-z0-9\-_]+)=\""([^""]+)\""", RegexOptions.IgnoreCase);
-            var matches = reg.Matches(properties);
+            var matches = reg.Matches(line);
+            var minIndex = int.MaxValue;
             foreach (Match match in matches)
             foreach (Match match in matches)
             {
             {
-                if (match.Groups[1].Value == property)
-                {
-                    return match.Groups[2].Value;
-                }
+                dict[match.Groups[1].Value] = match.Groups[2].Value;
+                minIndex = Math.Min(minIndex, match.Index);
             }
             }
-            return null;
+
+            if (minIndex > 0 && minIndex < line.Length)
+            {
+                line = line.Substring(0, minIndex);
+            }
+
+            remaining = line;
+
+            return dict;
         }
         }
     }
     }
 
 

+ 1 - 1
MediaBrowser.Api/Playback/Hls/BaseHlsService.cs

@@ -258,7 +258,7 @@ namespace MediaBrowser.Api.Playback.Hls
             // add when stream copying? 
             // add when stream copying? 
             // -avoid_negative_ts make_zero -fflags +genpts
             // -avoid_negative_ts make_zero -fflags +genpts
 
 
-            var args = string.Format("{0} {1} {2} -map_metadata -1 -threads {3} {4} {5} -fflags +genpts -sc_threshold 0 {6} -hls_time {7} -start_number {8} -hls_list_size {9}{10} -y \"{11}\"",
+            var args = string.Format("{0} {1} {2} -map_metadata -1 -map_chapters -1 -threads {3} {4} {5} -fflags +genpts -sc_threshold 0 {6} -hls_time {7} -start_number {8} -hls_list_size {9}{10} -y \"{11}\"",
                 itsOffset,
                 itsOffset,
                 inputModifier,
                 inputModifier,
                 GetInputArgument(state),
                 GetInputArgument(state),

+ 2 - 2
MediaBrowser.Api/Playback/Hls/DynamicHlsService.cs

@@ -895,7 +895,7 @@ namespace MediaBrowser.Api.Playback.Hls
             {
             {
                 var outputTsArg = Path.Combine(Path.GetDirectoryName(outputPath), Path.GetFileNameWithoutExtension(outputPath)) + "%d" + GetSegmentFileExtension(state);
                 var outputTsArg = Path.Combine(Path.GetDirectoryName(outputPath), Path.GetFileNameWithoutExtension(outputPath)) + "%d" + GetSegmentFileExtension(state);
 
 
-                return string.Format("{0} {10} {1} -map_metadata -1 -threads {2} {3} {4} {5} -f segment -max_delay 5000000 -avoid_negative_ts disabled -start_at_zero -segment_time {6} -break_non_keyframes  1 -segment_format mpegts -segment_list_type m3u8 -segment_start_number {7} -segment_list \"{8}\" -y \"{9}\"",
+                return string.Format("{0} {10} {1} -map_metadata -1 -map_chapters -1 -threads {2} {3} {4} {5} -f segment -max_delay 5000000 -avoid_negative_ts disabled -start_at_zero -segment_time {6} -break_non_keyframes  1 -segment_format mpegts -segment_list_type m3u8 -segment_start_number {7} -segment_list \"{8}\" -y \"{9}\"",
                     inputModifier,
                     inputModifier,
                     GetInputArgument(state),
                     GetInputArgument(state),
                     threads,
                     threads,
@@ -913,7 +913,7 @@ namespace MediaBrowser.Api.Playback.Hls
             var splitByTime = hlsProtocolSupportsSplittingByTime && enableSplittingOnNonKeyFrames;
             var splitByTime = hlsProtocolSupportsSplittingByTime && enableSplittingOnNonKeyFrames;
             var splitByTimeArg = splitByTime ? " -hls_flags split_by_time" : "";
             var splitByTimeArg = splitByTime ? " -hls_flags split_by_time" : "";
 
 
-            return string.Format("{0}{12} {1} -map_metadata -1 -threads {2} {3} {4}{5} {6} -max_delay 5000000 -avoid_negative_ts disabled -start_at_zero -hls_time {7}{8} -start_number {9} -hls_list_size {10} -y \"{11}\"",
+            return string.Format("{0}{12} {1} -map_metadata -1 -map_chapters -1 -threads {2} {3} {4}{5} {6} -max_delay 5000000 -avoid_negative_ts disabled -start_at_zero -hls_time {7}{8} -start_number {9} -hls_list_size {10} -y \"{11}\"",
                             inputModifier,
                             inputModifier,
                             GetInputArgument(state),
                             GetInputArgument(state),
                             threads,
                             threads,

+ 1 - 1
MediaBrowser.Api/Playback/Progressive/VideoService.cs

@@ -111,7 +111,7 @@ namespace MediaBrowser.Api.Playback.Progressive
 
 
             var inputModifier = GetInputModifier(state);
             var inputModifier = GetInputModifier(state);
 
 
-            return string.Format("{0} {1}{2} {3} {4} -map_metadata -1 -threads {5} {6}{7} -y \"{8}\"",
+            return string.Format("{0} {1}{2} {3} {4} -map_metadata -1 -map_chapters -1 -threads {5} {6}{7} -y \"{8}\"",
                 inputModifier,
                 inputModifier,
                 GetInputArgument(state),
                 GetInputArgument(state),
                 keyFrame,
                 keyFrame,

+ 0 - 1
MediaBrowser.Api/Reports/Common/ReportViewType.cs

@@ -3,7 +3,6 @@ namespace MediaBrowser.Api.Reports
 	public enum ReportViewType
 	public enum ReportViewType
 	{
 	{
         ReportData,
         ReportData,
-        ReportStatistics,
         ReportActivities
         ReportActivities
 
 
 	}
 	}

+ 3 - 10
MediaBrowser.Api/Reports/ReportRequests.cs

@@ -60,7 +60,7 @@ namespace MediaBrowser.Api.Reports
     {
     {
         /// <summary> Gets or sets the report view. </summary>
         /// <summary> Gets or sets the report view. </summary>
         /// <value> The report view. </value>
         /// <value> The report view. </value>
-        [ApiMember(Name = "ReportView", Description = "The report view. Values (ReportData, ReportStatistics, ReportActivities)", IsRequired = true, DataType = "string", ParameterType = "query", Verb = "GET")]
+        [ApiMember(Name = "ReportView", Description = "The report view. Values (ReportData, ReportActivities)", IsRequired = true, DataType = "string", ParameterType = "query", Verb = "GET")]
         public string ReportView { get; set; }
         public string ReportView { get; set; }
         
         
         /// <summary> Gets or sets the report view. </summary>
         /// <summary> Gets or sets the report view. </summary>
@@ -101,7 +101,7 @@ namespace MediaBrowser.Api.Reports
     {
     {
         /// <summary> Gets or sets the report view. </summary>
         /// <summary> Gets or sets the report view. </summary>
         /// <value> The report view. </value>
         /// <value> The report view. </value>
-        [ApiMember(Name = "ReportView", Description = "The report view. Values (ReportData, ReportStatistics, ReportActivities)", IsRequired = true, DataType = "string", ParameterType = "query", Verb = "GET")]
+        [ApiMember(Name = "ReportView", Description = "The report view. Values (ReportData, ReportActivities)", IsRequired = true, DataType = "string", ParameterType = "query", Verb = "GET")]
         public string ReportView { get; set; }
         public string ReportView { get; set; }
 
 
         /// <summary> Gets or sets the report view. </summary>
         /// <summary> Gets or sets the report view. </summary>
@@ -120,13 +120,6 @@ namespace MediaBrowser.Api.Reports
         public string ReportColumns { get; set; }
         public string ReportColumns { get; set; }
 	}
 	}
 
 
-	[Route("/Reports/Statistics", "GET", Summary = "Gets reports statistics based on library items")]
-	public class GetReportStatistics : BaseReportRequest, IReturn<ReportStatResult>
-	{
-		public int? TopItems { get; set; }
-
-	}
-
 	[Route("/Reports/Items/Download", "GET", Summary = "Downloads report")]
 	[Route("/Reports/Items/Download", "GET", Summary = "Downloads report")]
     public class GetReportDownload : BaseReportRequest, IReportsDownload
     public class GetReportDownload : BaseReportRequest, IReportsDownload
 	{
 	{
@@ -150,7 +143,7 @@ namespace MediaBrowser.Api.Reports
     {
     {
         /// <summary> Gets or sets the report view. </summary>
         /// <summary> Gets or sets the report view. </summary>
         /// <value> The report view. </value>
         /// <value> The report view. </value>
-        [ApiMember(Name = "ReportView", Description = "The report view. Values (ReportData, ReportStatistics, ReportActivities)", IsRequired = true, DataType = "string", ParameterType = "query", Verb = "GET")]
+        [ApiMember(Name = "ReportView", Description = "The report view. Values (ReportData, ReportActivities)", IsRequired = true, DataType = "string", ParameterType = "query", Verb = "GET")]
         public string ReportView { get; set; }
         public string ReportView { get; set; }
 
 
         /// <summary> Gets or sets the report view. </summary>
         /// <summary> Gets or sets the report view. </summary>

+ 0 - 31
MediaBrowser.Api/Reports/ReportsService.cs

@@ -82,8 +82,6 @@ namespace MediaBrowser.Api.Reports
                     ReportBuilder dataBuilder = new ReportBuilder(_libraryManager);
                     ReportBuilder dataBuilder = new ReportBuilder(_libraryManager);
                     result = dataBuilder.GetHeaders(request);
                     result = dataBuilder.GetHeaders(request);
                     break;
                     break;
-                case ReportViewType.ReportStatistics:
-                    break;
                 case ReportViewType.ReportActivities:
                 case ReportViewType.ReportActivities:
                     ReportActivitiesBuilder activityBuilder = new ReportActivitiesBuilder(_libraryManager, _userManager);
                     ReportActivitiesBuilder activityBuilder = new ReportActivitiesBuilder(_libraryManager, _userManager);
                     result = activityBuilder.GetHeaders(request);
                     result = activityBuilder.GetHeaders(request);
@@ -109,20 +107,6 @@ namespace MediaBrowser.Api.Reports
             return ToOptimizedResult(reportResult);
             return ToOptimizedResult(reportResult);
         }
         }
 
 
-        /// <summary> Gets the given request. </summary>
-        /// <param name="request"> The request. </param>
-        /// <returns> A Task&lt;object&gt; </returns>
-        public async Task<object> Get(GetReportStatistics request)
-        {
-            if (string.IsNullOrEmpty(request.IncludeItemTypes))
-                return null;
-            request.DisplayType = "Screen";
-            var user = !string.IsNullOrWhiteSpace(request.UserId) ? _userManager.GetUserById(request.UserId) : null;
-            var reportResult = await GetReportStatistic(request, user);
-
-            return ToOptimizedResult(reportResult);
-        }
-
         /// <summary> Gets the given request. </summary>
         /// <summary> Gets the given request. </summary>
         /// <param name="request"> The request. </param>
         /// <param name="request"> The request. </param>
         /// <returns> A Task&lt;object&gt; </returns>
         /// <returns> A Task&lt;object&gt; </returns>
@@ -155,7 +139,6 @@ namespace MediaBrowser.Api.Reports
             ReportResult result = null;
             ReportResult result = null;
             switch (reportViewType)
             switch (reportViewType)
             {
             {
-                case ReportViewType.ReportStatistics:
                 case ReportViewType.ReportData:
                 case ReportViewType.ReportData:
                     ReportIncludeItemTypes reportRowType = ReportHelper.GetRowType(request.IncludeItemTypes);
                     ReportIncludeItemTypes reportRowType = ReportHelper.GetRowType(request.IncludeItemTypes);
                     ReportBuilder dataBuilder = new ReportBuilder(_libraryManager);
                     ReportBuilder dataBuilder = new ReportBuilder(_libraryManager);
@@ -463,20 +446,6 @@ namespace MediaBrowser.Api.Reports
             return reportResult;
             return reportResult;
         }
         }
 
 
-        /// <summary> Gets report statistic. </summary>
-        /// <param name="request"> The request. </param>
-        /// <returns> The report statistic. </returns>
-        private async Task<ReportStatResult> GetReportStatistic(GetReportStatistics request, User user)
-        {
-            ReportIncludeItemTypes reportRowType = ReportHelper.GetRowType(request.IncludeItemTypes);
-            QueryResult<BaseItem> queryResult = await GetQueryResult(request, user).ConfigureAwait(false);
-
-            ReportStatBuilder reportBuilder = new ReportStatBuilder(_libraryManager);
-            ReportStatResult reportResult = reportBuilder.GetResult(queryResult.Items, ReportHelper.GetRowType(request.IncludeItemTypes), request.TopItems ?? 5);
-            reportResult.TotalRecordCount = reportResult.Groups.Count();
-            return reportResult;
-        }
-
         #endregion
         #endregion
 
 
     }
     }

+ 11 - 1
MediaBrowser.Controller/Entities/TV/Episode.cs

@@ -3,6 +3,7 @@ using MediaBrowser.Model.Configuration;
 using MediaBrowser.Model.Entities;
 using MediaBrowser.Model.Entities;
 using System;
 using System;
 using System.Collections.Generic;
 using System.Collections.Generic;
+using System.Globalization;
 using System.Linq;
 using System.Linq;
 using MediaBrowser.Model.Serialization;
 using MediaBrowser.Model.Serialization;
 
 
@@ -184,7 +185,16 @@ namespace MediaBrowser.Controller.Entities.TV
 
 
         public string FindSeasonName()
         public string FindSeasonName()
         {
         {
-            var season = Season;
+            var season = Season;
+
+            if (season == null)
+            {
+                if (ParentIndexNumber.HasValue)
+                {
+                    return "Season " + ParentIndexNumber.Value.ToString(CultureInfo.InvariantCulture);
+                }
+            }
+
             return season == null ? SeasonName : season.Name;
             return season == null ? SeasonName : season.Name;
         }
         }
 
 

+ 0 - 1
MediaBrowser.LocalMetadata/MediaBrowser.LocalMetadata.csproj

@@ -59,7 +59,6 @@
     <Compile Include="Providers\GameXmlProvider.cs" />
     <Compile Include="Providers\GameXmlProvider.cs" />
     <Compile Include="Providers\MovieXmlProvider.cs" />
     <Compile Include="Providers\MovieXmlProvider.cs" />
     <Compile Include="Providers\MusicVideoXmlProvider.cs" />
     <Compile Include="Providers\MusicVideoXmlProvider.cs" />
-    <Compile Include="Providers\PersonXmlProvider.cs" />
     <Compile Include="Providers\PlaylistXmlProvider.cs" />
     <Compile Include="Providers\PlaylistXmlProvider.cs" />
     <Compile Include="Providers\SeriesXmlProvider.cs" />
     <Compile Include="Providers\SeriesXmlProvider.cs" />
     <Compile Include="Providers\VideoXmlProvider.cs" />
     <Compile Include="Providers\VideoXmlProvider.cs" />

+ 0 - 38
MediaBrowser.LocalMetadata/Providers/PersonXmlProvider.cs

@@ -1,38 +0,0 @@
-using System.IO;
-using System.Threading;
-using MediaBrowser.Common.IO;
-using MediaBrowser.Model.IO;
-using MediaBrowser.Controller.Entities;
-using MediaBrowser.Controller.IO;
-using MediaBrowser.Controller.Providers;
-using MediaBrowser.LocalMetadata.Parsers;
-using MediaBrowser.Model.Logging;
-using MediaBrowser.Model.Xml;
-
-namespace MediaBrowser.LocalMetadata.Providers
-{
-    //public class PersonXmlProvider : BaseXmlProvider<Person>
-    //{
-    //    private readonly ILogger _logger;
-    //    private readonly IProviderManager _providerManager;
-    //    protected IXmlReaderSettingsFactory XmlReaderSettingsFactory { get; private set; }
-
-    //    public PersonXmlProvider(IFileSystem fileSystem, ILogger logger, IProviderManager providerManager, IXmlReaderSettingsFactory xmlReaderSettingsFactory)
-    //        : base(fileSystem)
-    //    {
-    //        _logger = logger;
-    //        _providerManager = providerManager;
-    //        XmlReaderSettingsFactory = xmlReaderSettingsFactory;
-    //    }
-
-    //    protected override void Fetch(MetadataResult<Person> result, string path, CancellationToken cancellationToken)
-    //    {
-    //        new BaseItemXmlParser<Person>(_logger, _providerManager, XmlReaderSettingsFactory, FileSystem).Fetch(result, path, cancellationToken);
-    //    }
-
-    //    protected override FileSystemMetadata GetXmlFile(ItemInfo info, IDirectoryService directoryService)
-    //    {
-    //        return directoryService.GetFile(Path.Combine(info.Path, "person.xml"));
-    //    }
-    //}
-}

+ 2 - 0
MediaBrowser.Model/Dto/BaseItemDto.cs

@@ -729,6 +729,8 @@ namespace MediaBrowser.Model.Dto
         /// <value>The series studio.</value>
         /// <value>The series studio.</value>
         public string SeriesStudio { get; set; }
         public string SeriesStudio { get; set; }
 
 
+        public StudioDto SeriesStudioInfo { get; set; }
+
         /// <summary>
         /// <summary>
         /// Gets or sets the parent thumb item id.
         /// Gets or sets the parent thumb item id.
         /// </summary>
         /// </summary>

+ 12 - 0
MediaBrowser.Model/Net/ISocket.cs

@@ -4,6 +4,7 @@ namespace MediaBrowser.Model.Net
 {
 {
     public interface ISocket : IDisposable
     public interface ISocket : IDisposable
     {
     {
+        bool DualMode { get; }
         IpEndPointInfo LocalEndPoint { get; }
         IpEndPointInfo LocalEndPoint { get; }
         IpEndPointInfo RemoteEndPoint { get; }
         IpEndPointInfo RemoteEndPoint { get; }
         void Close();
         void Close();
@@ -13,4 +14,15 @@ namespace MediaBrowser.Model.Net
 
 
         void StartAccept(Action<ISocket> onAccept, Func<bool> isClosed);
         void StartAccept(Action<ISocket> onAccept, Func<bool> isClosed);
     }
     }
+
+    public class SocketCreateException : Exception
+    {
+        public SocketCreateException(string errorCode, Exception originalException)
+            : base(errorCode, originalException)
+        {
+            ErrorCode = errorCode;
+        }
+
+        public string ErrorCode { get; private set; }
+    }
 }
 }

+ 3 - 1
RSSDP/SsdpDevicePublisherBase.cs

@@ -249,7 +249,7 @@ namespace Rssdp.Infrastructure
 
 
             if (IsDuplicateSearchRequest(searchTarget, remoteEndPoint))
             if (IsDuplicateSearchRequest(searchTarget, remoteEndPoint))
             {
             {
-                WriteTrace("Search Request is Duplicate, ignoring.");
+                //WriteTrace("Search Request is Duplicate, ignoring.");
                 return;
                 return;
             }
             }
 
 
@@ -299,7 +299,9 @@ namespace Rssdp.Infrastructure
                     }
                     }
                 }
                 }
                 else
                 else
+                {
                     WriteTrace(String.Format("Sending 0 search responses."));
                     WriteTrace(String.Format("Sending 0 search responses."));
+                }
             });
             });
         }
         }
 
 

+ 18 - 2
SocketHttpListener.Portable/Net/EndPointListener.cs

@@ -26,7 +26,7 @@ namespace SocketHttpListener.Net
         Dictionary<HttpConnection, HttpConnection> unregistered;
         Dictionary<HttpConnection, HttpConnection> unregistered;
         private readonly ILogger _logger;
         private readonly ILogger _logger;
         private bool _closed;
         private bool _closed;
-        private readonly bool _enableDualMode;
+        private bool _enableDualMode;
         private readonly ICryptoProvider _cryptoProvider;
         private readonly ICryptoProvider _cryptoProvider;
         private readonly IStreamFactory _streamFactory;
         private readonly IStreamFactory _streamFactory;
         private readonly ISocketFactory _socketFactory;
         private readonly ISocketFactory _socketFactory;
@@ -65,7 +65,23 @@ namespace SocketHttpListener.Net
 
 
         private void CreateSocket()
         private void CreateSocket()
         {
         {
-            sock = _socketFactory.CreateSocket(endpoint.IpAddress.AddressFamily, SocketType.Stream, ProtocolType.Tcp, _enableDualMode);
+            try
+            {
+                sock = _socketFactory.CreateSocket(endpoint.IpAddress.AddressFamily, SocketType.Stream, ProtocolType.Tcp, _enableDualMode);
+            }
+            catch (SocketCreateException ex)
+            {
+                if (_enableDualMode && endpoint.IpAddress.Equals(IpAddressInfo.IPv6Any) && string.Equals(ex.ErrorCode, "AddressFamilyNotSupported", StringComparison.OrdinalIgnoreCase))
+                {
+                    endpoint = new IpEndPointInfo(IpAddressInfo.Any, endpoint.Port);
+                    _enableDualMode = false;
+                    sock = _socketFactory.CreateSocket(endpoint.IpAddress.AddressFamily, SocketType.Stream, ProtocolType.Tcp, _enableDualMode);
+                }
+                else
+                {
+                    throw;
+                }
+            }
 
 
             sock.Bind(endpoint);
             sock.Bind(endpoint);