Bläddra i källkod

Merge branch 'master' of https://github.com/MediaBrowser/Emby

Luke Pulverenti 8 år sedan
förälder
incheckning
d5c7845917
100 ändrade filer med 1404 tillägg och 2372 borttagningar
  1. 10 3
      Emby.Common.Implementations/Net/NetAcceptSocket.cs
  2. 5 5
      Emby.Common.Implementations/Net/SocketAcceptor.cs
  3. 31 16
      Emby.Common.Implementations/Net/SocketFactory.cs
  4. 10 6
      Emby.Common.Implementations/Net/UdpSocket.cs
  5. 12 2
      Emby.Common.Implementations/Networking/NetworkManager.cs
  6. 6 0
      Emby.Dlna/Profiles/DefaultProfile.cs
  7. 9 0
      Emby.Dlna/Profiles/DirectTvProfile.cs
  8. 8 0
      Emby.Dlna/Profiles/DishHopperJoeyProfile.cs
  9. 9 0
      Emby.Dlna/Profiles/LinksysDMA2100Profile.cs
  10. 9 0
      Emby.Dlna/Profiles/PopcornHourProfile.cs
  11. 9 0
      Emby.Dlna/Profiles/SonyBlurayPlayerProfile.cs
  12. 9 0
      Emby.Dlna/Profiles/SonyBravia2010Profile.cs
  13. 9 0
      Emby.Dlna/Profiles/SonyBravia2011Profile.cs
  14. 9 0
      Emby.Dlna/Profiles/SonyBravia2012Profile.cs
  15. 9 0
      Emby.Dlna/Profiles/SonyBravia2013Profile.cs
  16. 9 0
      Emby.Dlna/Profiles/SonyBravia2014Profile.cs
  17. 9 0
      Emby.Dlna/Profiles/SonyPs3Profile.cs
  18. 9 0
      Emby.Dlna/Profiles/SonyPs4Profile.cs
  19. 1 1
      Emby.Dlna/Profiles/WdtvLiveProfile.cs
  20. 9 0
      Emby.Dlna/Profiles/Xbox360Profile.cs
  21. 9 0
      Emby.Dlna/Profiles/XboxOneProfile.cs
  22. 1 0
      Emby.Dlna/Profiles/Xml/Default.xml
  23. 1 0
      Emby.Dlna/Profiles/Xml/Denon AVR.xml
  24. 1 0
      Emby.Dlna/Profiles/Xml/MediaMonkey.xml
  25. 1 1
      Emby.Dlna/Profiles/Xml/WDTV Live.xml
  26. 1 0
      Emby.Dlna/Profiles/Xml/foobar2000.xml
  27. 3 1
      Emby.Drawing.ImageMagick/ImageMagickEncoder.cs
  28. 2 2
      Emby.Server.Core/HttpServerFactory.cs
  29. 9 1
      Emby.Server.Core/Localization/TextLocalizer.cs
  30. 5 5
      Emby.Server.Implementations/Data/SqliteItemRepository.cs
  31. 3 4
      Emby.Server.Implementations/Devices/DeviceManager.cs
  32. 1 1
      Emby.Server.Implementations/Dto/DtoService.cs
  33. 3 4
      Emby.Server.Implementations/Emby.Server.Implementations.csproj
  34. 1 2
      Emby.Server.Implementations/HttpServer/HttpListenerHost.cs
  35. 0 394
      Emby.Server.Implementations/Intros/DefaultIntroProvider.cs
  36. 30 8
      Emby.Server.Implementations/Library/LibraryManager.cs
  37. 5 0
      Emby.Server.Implementations/Library/UserManager.cs
  38. 11 1
      Emby.Server.Implementations/LiveTv/Listings/SchedulesDirect.cs
  39. 5 2
      Emby.Server.Implementations/LiveTv/LiveStreamHelper.cs
  40. 1 0
      Emby.Server.Implementations/LiveTv/LiveTvManager.cs
  41. 198 120
      Emby.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunHost.cs
  42. 2 2
      Emby.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunHttpStream.cs
  43. 453 0
      Emby.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunManager.cs
  44. 294 0
      Emby.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunUdpStream.cs
  45. 0 1
      Emby.Server.Implementations/LiveTv/TunerHosts/M3UTunerHost.cs
  46. 0 19
      Emby.Server.Implementations/LiveTv/TunerHosts/MulticastStream.cs
  47. 0 39
      Emby.Server.Implementations/Sorting/BudgetComparer.cs
  48. 0 39
      Emby.Server.Implementations/Sorting/RevenueComparer.cs
  49. 2 2
      Emby.Server.Implementations/Udp/UdpServer.cs
  50. 9 9
      Emby.Server.Implementations/Updates/InstallationManager.cs
  51. 0 4
      MediaBrowser.Api/MediaBrowser.Api.csproj
  52. 1 0
      MediaBrowser.Api/Playback/Progressive/AudioService.cs
  53. 0 85
      MediaBrowser.Api/Sync/SyncHelper.cs
  54. 0 120
      MediaBrowser.Api/Sync/SyncJobWebSocketListener.cs
  55. 0 101
      MediaBrowser.Api/Sync/SyncJobsWebSocketListener.cs
  56. 0 396
      MediaBrowser.Api/Sync/SyncService.cs
  57. 3 1
      MediaBrowser.Common/Net/INetworkManager.cs
  58. 0 10
      MediaBrowser.Controller/Entities/Folder.cs
  59. 0 18
      MediaBrowser.Controller/Entities/IHasBudget.cs
  60. 1 13
      MediaBrowser.Controller/Entities/Movies/Movie.cs
  61. 1 12
      MediaBrowser.Controller/Entities/MusicVideo.cs
  62. 1 1
      MediaBrowser.Controller/LiveTv/LiveTvChannel.cs
  63. 0 1
      MediaBrowser.Controller/MediaBrowser.Controller.csproj
  64. 0 8
      MediaBrowser.Controller/MediaEncoding/IMediaEncoder.cs
  65. 1 1
      MediaBrowser.Controller/MediaEncoding/MediaInfoRequest.cs
  66. 1 1
      MediaBrowser.LocalMetadata/Images/LocalImageProvider.cs
  67. 0 32
      MediaBrowser.LocalMetadata/Parsers/BaseItemXmlParser.cs
  68. 0 16
      MediaBrowser.LocalMetadata/Savers/BaseXmlSaver.cs
  69. 6 1
      MediaBrowser.MediaEncoding/Encoder/EncoderValidator.cs
  70. 0 10
      MediaBrowser.MediaEncoding/Encoder/EncodingUtils.cs
  71. 22 35
      MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs
  72. 26 3
      MediaBrowser.MediaEncoding/Probing/ProbeResultNormalizer.cs
  73. 11 6
      MediaBrowser.MediaEncoding/Subtitles/SubtitleEncoder.cs
  74. 0 66
      MediaBrowser.Model/Dto/BaseItemDto.cs
  75. 2 0
      MediaBrowser.Model/Dto/MediaSourceInfo.cs
  76. 3 1
      MediaBrowser.Model/Dto/UserDto.cs
  77. 1 0
      MediaBrowser.Model/LiveTv/LiveTvOptions.cs
  78. 2 2
      MediaBrowser.Model/MediaBrowser.Model.csproj
  79. 28 0
      MediaBrowser.Model/Net/IAcceptSocket.cs
  80. 19 19
      MediaBrowser.Model/Net/ISocket.cs
  81. 9 7
      MediaBrowser.Model/Net/ISocketFactory.cs
  82. 0 28
      MediaBrowser.Model/Net/IUdpSocket.cs
  83. 3 0
      MediaBrowser.Model/Net/MimeTypes.cs
  84. 2 10
      MediaBrowser.Model/Querying/ItemFields.cs
  85. 0 8
      MediaBrowser.Model/Querying/ItemSortBy.cs
  86. 4 0
      MediaBrowser.Model/Session/PlaybackProgressInfo.cs
  87. 1 0
      MediaBrowser.Providers/Manager/ImageSaver.cs
  88. 0 20
      MediaBrowser.Providers/Manager/ProviderUtils.cs
  89. 0 7
      MediaBrowser.Providers/Movies/GenericMovieDbInfo.cs
  90. 0 5
      MediaBrowser.Providers/TV/TheTVDB/TvdbSeriesProvider.cs
  91. 9 15
      MediaBrowser.Server.Mac/Emby.Server.Mac.csproj
  92. 3 0
      MediaBrowser.Server.Mono/MediaBrowser.Server.Mono.csproj
  93. 2 0
      MediaBrowser.Server.Mono/MonoAppHost.cs
  94. 0 105
      MediaBrowser.Server.Startup.Common/LiveTv/TunerHosts/SatIp/ChannelScan.cs
  95. 0 79
      MediaBrowser.Server.Startup.Common/LiveTv/TunerHosts/SatIp/Rtcp/ReportBlock.cs
  96. 0 68
      MediaBrowser.Server.Startup.Common/LiveTv/TunerHosts/SatIp/Rtcp/RtcpAppPacket.cs
  97. 0 59
      MediaBrowser.Server.Startup.Common/LiveTv/TunerHosts/SatIp/Rtcp/RtcpByePacket.cs
  98. 0 203
      MediaBrowser.Server.Startup.Common/LiveTv/TunerHosts/SatIp/Rtcp/RtcpListener.cs
  99. 0 37
      MediaBrowser.Server.Startup.Common/LiveTv/TunerHosts/SatIp/Rtcp/RtcpPacket.cs
  100. 0 68
      MediaBrowser.Server.Startup.Common/LiveTv/TunerHosts/SatIp/Rtcp/RtcpReceiverReportPacket.cs

+ 10 - 3
Emby.Common.Implementations/Net/NetSocket.cs → Emby.Common.Implementations/Net/NetAcceptSocket.cs

@@ -8,14 +8,14 @@ using MediaBrowser.Model.Logging;
 
 namespace Emby.Common.Implementations.Net
 {
-    public class NetSocket : ISocket
+    public class NetAcceptSocket : IAcceptSocket
     {
         public Socket Socket { get; private set; }
         private readonly ILogger _logger;
 
         public bool DualMode { get; private set; }
 
-        public NetSocket(Socket socket, ILogger logger, bool isDualMode)
+        public NetAcceptSocket(Socket socket, ILogger logger, bool isDualMode)
         {
             if (socket == null)
             {
@@ -47,6 +47,13 @@ namespace Emby.Common.Implementations.Net
             }
         }
 
+        public void Connect(IpEndPointInfo endPoint)
+        {
+            var nativeEndpoint = NetworkManager.ToIPEndPoint(endPoint);
+
+            Socket.Connect(nativeEndpoint);
+        }
+
         public void Close()
         {
 #if NET46
@@ -82,7 +89,7 @@ namespace Emby.Common.Implementations.Net
         }
 
         private SocketAcceptor _acceptor;
-        public void StartAccept(Action<ISocket> onAccept, Func<bool> isClosed)
+        public void StartAccept(Action<IAcceptSocket> onAccept, Func<bool> isClosed)
         {
             _acceptor = new SocketAcceptor(_logger, Socket, onAccept, isClosed, DualMode);
 

+ 5 - 5
Emby.Common.Implementations/Net/SocketAcceptor.cs

@@ -10,10 +10,10 @@ namespace Emby.Common.Implementations.Net
         private readonly ILogger _logger;
         private readonly Socket _originalSocket;
         private readonly Func<bool> _isClosed;
-        private readonly Action<ISocket> _onAccept;
+        private readonly Action<IAcceptSocket> _onAccept;
         private readonly bool _isDualMode;
 
-        public SocketAcceptor(ILogger logger, Socket originalSocket, Action<ISocket> onAccept, Func<bool> isClosed, bool isDualMode)
+        public SocketAcceptor(ILogger logger, Socket originalSocket, Action<IAcceptSocket> onAccept, Func<bool> isClosed, bool isDualMode)
         {
             if (logger == null)
             {
@@ -54,7 +54,7 @@ namespace Emby.Common.Implementations.Net
             }
             else
             {
-                // socket must be cleared since the context object is being reused
+                // acceptSocket must be cleared since the context object is being reused
                 acceptEventArg.AcceptSocket = null;
             }
 
@@ -102,7 +102,7 @@ namespace Emby.Common.Implementations.Net
                 return;
             }
 
-            // http://msdn.microsoft.com/en-us/library/system.net.sockets.socket.acceptasync%28v=vs.110%29.aspx
+            // http://msdn.microsoft.com/en-us/library/system.net.sockets.acceptSocket.acceptasync%28v=vs.110%29.aspx
             // Under certain conditions ConnectionReset can occur
             // Need to attept to re-accept
             if (e.SocketError == SocketError.ConnectionReset)
@@ -117,7 +117,7 @@ namespace Emby.Common.Implementations.Net
             if (acceptSocket != null)
             {
                 //ProcessAccept(acceptSocket);
-                _onAccept(new NetSocket(acceptSocket, _logger, _isDualMode));
+                _onAccept(new NetAcceptSocket(acceptSocket, _logger, _isDualMode));
             }
 
             // Accept the next connection request

+ 31 - 16
Emby.Common.Implementations/Net/SocketFactory.cs

@@ -31,7 +31,7 @@ namespace Emby.Common.Implementations.Net
             _logger = logger;
         }
 
-        public ISocket CreateSocket(IpAddressFamily family, MediaBrowser.Model.Net.SocketType socketType, MediaBrowser.Model.Net.ProtocolType protocolType, bool dualMode)
+        public IAcceptSocket CreateSocket(IpAddressFamily family, MediaBrowser.Model.Net.SocketType socketType, MediaBrowser.Model.Net.ProtocolType protocolType, bool dualMode)
         {
             try
             {
@@ -46,7 +46,7 @@ namespace Emby.Common.Implementations.Net
                     socket.DualMode = true;
                 }
 
-                return new NetSocket(socket, _logger, dualMode);
+                return new NetAcceptSocket(socket, _logger, dualMode);
             }
             catch (SocketException ex)
             {
@@ -54,13 +54,30 @@ namespace Emby.Common.Implementations.Net
             }
         }
 
-        #region ISocketFactory Members
+        public ISocket CreateTcpSocket(IpAddressInfo remoteAddress, int remotePort)
+        {
+            if (remotePort < 0) throw new ArgumentException("remotePort cannot be less than zero.", "remotePort");
+
+            var retVal = new Socket(AddressFamily.InterNetwork, System.Net.Sockets.SocketType.Stream, System.Net.Sockets.ProtocolType.Tcp);
+            try
+            {
+                retVal.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, true);
+                return new UdpSocket(retVal, new IpEndPointInfo(remoteAddress, remotePort));
+            }
+            catch
+            {
+                if (retVal != null)
+                    retVal.Dispose();
+
+                throw;
+            }
+        }
 
         /// <summary>
-        /// Creates a new UDP socket and binds it to the specified local port.
+        /// Creates a new UDP acceptSocket and binds it to the specified local port.
         /// </summary>
-        /// <param name="localPort">An integer specifying the local port to bind the socket to.</param>
-        public IUdpSocket CreateUdpSocket(int localPort)
+        /// <param name="localPort">An integer specifying the local port to bind the acceptSocket to.</param>
+        public ISocket CreateUdpSocket(int localPort)
         {
             if (localPort < 0) throw new ArgumentException("localPort cannot be less than zero.", "localPort");
 
@@ -80,10 +97,10 @@ namespace Emby.Common.Implementations.Net
         }
 
         /// <summary>
-        /// Creates a new UDP socket that is a member of the SSDP multicast local admin group and binds it to the specified local port.
+        /// Creates a new UDP acceptSocket that is a member of the SSDP multicast local admin group and binds it to the specified local port.
         /// </summary>
-        /// <returns>An implementation of the <see cref="IUdpSocket"/> interface used by RSSDP components to perform socket operations.</returns>
-        public IUdpSocket CreateSsdpUdpSocket(IpAddressInfo localIpAddress, int localPort)
+        /// <returns>An implementation of the <see cref="ISocket"/> interface used by RSSDP components to perform acceptSocket operations.</returns>
+        public ISocket CreateSsdpUdpSocket(IpAddressInfo localIpAddress, int localPort)
         {
             if (localPort < 0) throw new ArgumentException("localPort cannot be less than zero.", "localPort");
 
@@ -108,13 +125,13 @@ namespace Emby.Common.Implementations.Net
         }
 
         /// <summary>
-        /// Creates a new UDP socket that is a member of the specified multicast IP address, and binds it to the specified local port.
+        /// Creates a new UDP acceptSocket that is a member of the specified multicast IP address, and binds it to the specified local port.
         /// </summary>
-        /// <param name="ipAddress">The multicast IP address to make the socket a member of.</param>
-        /// <param name="multicastTimeToLive">The multicast time to live value for the socket.</param>
+        /// <param name="ipAddress">The multicast IP address to make the acceptSocket a member of.</param>
+        /// <param name="multicastTimeToLive">The multicast time to live value for the acceptSocket.</param>
         /// <param name="localPort">The number of the local port to bind to.</param>
         /// <returns></returns>
-        public IUdpSocket CreateUdpMulticastSocket(string ipAddress, int multicastTimeToLive, int localPort)
+        public ISocket CreateUdpMulticastSocket(string ipAddress, int multicastTimeToLive, int localPort)
         {
             if (ipAddress == null) throw new ArgumentNullException("ipAddress");
             if (ipAddress.Length == 0) throw new ArgumentException("ipAddress cannot be an empty string.", "ipAddress");
@@ -128,7 +145,7 @@ namespace Emby.Common.Implementations.Net
 #if NET46
 				retVal.ExclusiveAddressUse = false;
 #else
-                // The ExclusiveAddressUse socket option is a Windows-specific option that, when set to "true," tells Windows not to allow another socket to use the same local address as this socket
+                // The ExclusiveAddressUse acceptSocket option is a Windows-specific option that, when set to "true," tells Windows not to allow another acceptSocket to use the same local address as this acceptSocket
                 // See https://github.com/dotnet/corefx/pull/11509 for more details
                 if (System.Runtime.InteropServices.RuntimeInformation.IsOSPlatform(System.Runtime.InteropServices.OSPlatform.Windows))
 				{
@@ -154,7 +171,5 @@ namespace Emby.Common.Implementations.Net
                 throw;
             }
         }
-
-        #endregion
     }
 }

+ 10 - 6
Emby.Common.Implementations/Net/UdpSocket.cs

@@ -14,7 +14,7 @@ namespace Emby.Common.Implementations.Net
     // THIS IS A LINKED FILE - SHARED AMONGST MULTIPLE PLATFORMS	
     // Be careful to check any changes compile and work for all platform projects it is shared in.
 
-    internal sealed class UdpSocket : DisposableManagedObjectBase, IUdpSocket
+    internal sealed class UdpSocket : DisposableManagedObjectBase, ISocket
     {
 
         #region Fields
@@ -23,8 +23,6 @@ namespace Emby.Common.Implementations.Net
         private int _LocalPort;
         #endregion
 
-        #region Constructors
-
         public UdpSocket(Socket socket, int localPort, IPAddress ip)
         {
             if (socket == null) throw new ArgumentNullException("socket");
@@ -36,7 +34,13 @@ namespace Emby.Common.Implementations.Net
             _Socket.Bind(new IPEndPoint(ip, _LocalPort));
         }
 
-        #endregion
+        public UdpSocket(Socket socket, IpEndPointInfo endPoint)
+        {
+            if (socket == null) throw new ArgumentNullException("socket");
+
+            _Socket = socket;
+            _Socket.Connect(NetworkManager.ToIPEndPoint(endPoint));
+        }
 
         public IpAddressInfo LocalIPAddress
         {
@@ -44,9 +48,9 @@ namespace Emby.Common.Implementations.Net
             private set;
         }
 
-        #region IUdpSocket Members
+        #region ISocket Members
 
-        public Task<SocketReceiveResult> ReceiveAsync()
+        public Task<SocketReceiveResult> ReceiveAsync(CancellationToken cancellationToken)
         {
             ThrowIfDisposed();
 

+ 12 - 2
Emby.Common.Implementations/Networking/NetworkManager.cs

@@ -234,7 +234,7 @@ namespace Emby.Common.Implementations.Networking
                     // Try to exclude virtual adapters
                     // http://stackoverflow.com/questions/8089685/c-sharp-finding-my-machines-local-ip-address-and-not-the-vms
                     var addr = ipProperties.GatewayAddresses.FirstOrDefault();
-                    if (addr == null|| string.Equals(addr.Address.ToString(), "0.0.0.0", StringComparison.OrdinalIgnoreCase))
+                    if (addr == null || string.Equals(addr.Address.ToString(), "0.0.0.0", StringComparison.OrdinalIgnoreCase))
                     {
                         return new List<IPAddress>();
                     }
@@ -275,7 +275,7 @@ namespace Emby.Common.Implementations.Networking
         /// Gets a random port number that is currently available
         /// </summary>
         /// <returns>System.Int32.</returns>
-        public int GetRandomUnusedPort()
+        public int GetRandomUnusedTcpPort()
         {
             var listener = new TcpListener(IPAddress.Any, 0);
             listener.Start();
@@ -284,6 +284,16 @@ namespace Emby.Common.Implementations.Networking
             return port;
         }
 
+        public int GetRandomUnusedUdpPort()
+        {
+            IPEndPoint localEndPoint = new IPEndPoint(IPAddress.Any, 0);
+            using (var udpClient = new UdpClient(localEndPoint))
+            {
+                var port = ((IPEndPoint)(udpClient.Client.LocalEndPoint)).Port;
+                return port;
+            }
+        }
+
         /// <summary>
         /// Returns MAC Address from first Network Card in Computer
         /// </summary>

+ 6 - 0
Emby.Dlna/Profiles/DefaultProfile.cs

@@ -83,6 +83,12 @@ namespace Emby.Dlna.Profiles
                 {
                     Format = "srt",
                     Method = SubtitleDeliveryMethod.Embed
+                },
+
+                new SubtitleProfile
+                {
+                    Format = "srt",
+                    Method = SubtitleDeliveryMethod.External,
                 }
             };
 

+ 9 - 0
Emby.Dlna/Profiles/DirectTvProfile.cs

@@ -113,6 +113,15 @@ namespace Emby.Dlna.Profiles
                 }
             };
 
+            SubtitleProfiles = new[]
+            {
+                new SubtitleProfile
+                {
+                    Format = "srt",
+                    Method = SubtitleDeliveryMethod.Embed
+                }
+            };
+
             ResponseProfiles = new ResponseProfile[] { };
         }
     }

+ 8 - 0
Emby.Dlna/Profiles/DishHopperJoeyProfile.cs

@@ -214,6 +214,14 @@ namespace Emby.Dlna.Profiles
                 }
             };
 
+            SubtitleProfiles = new[]
+            {
+                new SubtitleProfile
+                {
+                    Format = "srt",
+                    Method = SubtitleDeliveryMethod.Embed
+                }
+            };
         }
     }
 }

+ 9 - 0
Emby.Dlna/Profiles/LinksysDMA2100Profile.cs

@@ -40,6 +40,15 @@ namespace Emby.Dlna.Profiles
                     MimeType = "video/mp4"
                 }
             };
+
+            SubtitleProfiles = new[]
+            {
+                new SubtitleProfile
+                {
+                    Format = "srt",
+                    Method = SubtitleDeliveryMethod.Embed
+                }
+            };
         }
     }
 }

+ 9 - 0
Emby.Dlna/Profiles/PopcornHourProfile.cs

@@ -210,6 +210,15 @@ namespace Emby.Dlna.Profiles
                     MimeType = "video/mp4"
                 }
             };
+
+            SubtitleProfiles = new[]
+            {
+                new SubtitleProfile
+                {
+                    Format = "srt",
+                    Method = SubtitleDeliveryMethod.Embed
+                }
+            };
         }
     }
 }

+ 9 - 0
Emby.Dlna/Profiles/SonyBlurayPlayerProfile.cs

@@ -269,6 +269,15 @@ namespace Emby.Dlna.Profiles
                     Type = DlnaProfileType.Audio
                 }
             };
+
+            SubtitleProfiles = new[]
+            {
+                new SubtitleProfile
+                {
+                    Format = "srt",
+                    Method = SubtitleDeliveryMethod.Embed
+                }
+            };
         }
     }
 }

+ 9 - 0
Emby.Dlna/Profiles/SonyBravia2010Profile.cs

@@ -351,6 +351,15 @@ namespace Emby.Dlna.Profiles
                     }
                 }
             };
+
+            SubtitleProfiles = new[]
+            {
+                new SubtitleProfile
+                {
+                    Format = "srt",
+                    Method = SubtitleDeliveryMethod.Embed
+                }
+            };
         }
     }
 }

+ 9 - 0
Emby.Dlna/Profiles/SonyBravia2011Profile.cs

@@ -374,6 +374,15 @@ namespace Emby.Dlna.Profiles
                     }
                 }
             };
+
+            SubtitleProfiles = new[]
+            {
+                new SubtitleProfile
+                {
+                    Format = "srt",
+                    Method = SubtitleDeliveryMethod.Embed
+                }
+            };
         }
     }
 }

+ 9 - 0
Emby.Dlna/Profiles/SonyBravia2012Profile.cs

@@ -292,6 +292,15 @@ namespace Emby.Dlna.Profiles
                     }
                 }
             };
+
+            SubtitleProfiles = new[]
+            {
+                new SubtitleProfile
+                {
+                    Format = "srt",
+                    Method = SubtitleDeliveryMethod.Embed
+                }
+            };
         }
     }
 }

+ 9 - 0
Emby.Dlna/Profiles/SonyBravia2013Profile.cs

@@ -310,6 +310,15 @@ namespace Emby.Dlna.Profiles
                     }
                 }
             };
+
+            SubtitleProfiles = new[]
+            {
+                new SubtitleProfile
+                {
+                    Format = "srt",
+                    Method = SubtitleDeliveryMethod.Embed
+                }
+            };
         }
     }
 }

+ 9 - 0
Emby.Dlna/Profiles/SonyBravia2014Profile.cs

@@ -310,6 +310,15 @@ namespace Emby.Dlna.Profiles
                     }
                 }
             };
+
+            SubtitleProfiles = new[]
+            {
+                new SubtitleProfile
+                {
+                    Format = "srt",
+                    Method = SubtitleDeliveryMethod.Embed
+                }
+            };
         }
     }
 }

+ 9 - 0
Emby.Dlna/Profiles/SonyPs3Profile.cs

@@ -255,6 +255,15 @@ namespace Emby.Dlna.Profiles
                     Type = DlnaProfileType.Audio
                 }
             };
+
+            SubtitleProfiles = new[]
+            {
+                new SubtitleProfile
+                {
+                    Format = "srt",
+                    Method = SubtitleDeliveryMethod.Embed
+                }
+            };
         }
     }
 }

+ 9 - 0
Emby.Dlna/Profiles/SonyPs4Profile.cs

@@ -264,6 +264,15 @@ namespace Emby.Dlna.Profiles
                     MimeType = "video/mp4"
                 }
             };
+
+            SubtitleProfiles = new[]
+            {
+                new SubtitleProfile
+                {
+                    Format = "srt",
+                    Method = SubtitleDeliveryMethod.Embed
+                }
+            };
         }
     }
 }

+ 1 - 1
Emby.Dlna/Profiles/WdtvLiveProfile.cs

@@ -125,7 +125,7 @@ namespace Emby.Dlna.Profiles
 
                 new DirectPlayProfile
                 {
-                    Container = "flac,ac3",
+                    Container = "flac",
                     Type = DlnaProfileType.Audio
                 },
 

+ 9 - 0
Emby.Dlna/Profiles/Xbox360Profile.cs

@@ -312,6 +312,15 @@ namespace Emby.Dlna.Profiles
                     }
                 }
             };
+
+            SubtitleProfiles = new[]
+            {
+                new SubtitleProfile
+                {
+                    Format = "srt",
+                    Method = SubtitleDeliveryMethod.Embed
+                }
+            };
         }
     }
 }

+ 9 - 0
Emby.Dlna/Profiles/XboxOneProfile.cs

@@ -357,6 +357,15 @@ namespace Emby.Dlna.Profiles
                     MimeType = "video/mp4"
                 }
             };
+
+            SubtitleProfiles = new[]
+            {
+                new SubtitleProfile
+                {
+                    Format = "srt",
+                    Method = SubtitleDeliveryMethod.Embed
+                }
+            };
         }
     }
 }

+ 1 - 0
Emby.Dlna/Profiles/Xml/Default.xml

@@ -46,5 +46,6 @@
   </ResponseProfiles>
   <SubtitleProfiles>
     <SubtitleProfile format="srt" method="Embed" />
+    <SubtitleProfile format="srt" method="External" />
   </SubtitleProfiles>
 </Profile>

+ 1 - 0
Emby.Dlna/Profiles/Xml/Denon AVR.xml

@@ -46,5 +46,6 @@
   <ResponseProfiles />
   <SubtitleProfiles>
     <SubtitleProfile format="srt" method="Embed" />
+    <SubtitleProfile format="srt" method="External" />
   </SubtitleProfiles>
 </Profile>

+ 1 - 0
Emby.Dlna/Profiles/Xml/MediaMonkey.xml

@@ -52,5 +52,6 @@
   <ResponseProfiles />
   <SubtitleProfiles>
     <SubtitleProfile format="srt" method="Embed" />
+    <SubtitleProfile format="srt" method="External" />
   </SubtitleProfiles>
 </Profile>

+ 1 - 1
Emby.Dlna/Profiles/Xml/WDTV Live.xml

@@ -45,7 +45,7 @@
     <DirectPlayProfile container="asf" audioCodec="mp2,ac3" videoCodec="mpeg2video" type="Video" />
     <DirectPlayProfile container="mp3" audioCodec="mp2,mp3" type="Audio" />
     <DirectPlayProfile container="mp4" audioCodec="mp4" type="Audio" />
-    <DirectPlayProfile container="flac,ac3" type="Audio" />
+    <DirectPlayProfile container="flac" type="Audio" />
     <DirectPlayProfile container="asf" audioCodec="wmav2,wmapro,wmavoice" type="Audio" />
     <DirectPlayProfile container="ogg" audioCodec="vorbis" type="Audio" />
     <DirectPlayProfile container="jpeg,png,gif,bmp,tiff" type="Photo" />

+ 1 - 0
Emby.Dlna/Profiles/Xml/foobar2000.xml

@@ -52,5 +52,6 @@
   <ResponseProfiles />
   <SubtitleProfiles>
     <SubtitleProfile format="srt" method="Embed" />
+    <SubtitleProfile format="srt" method="External" />
   </SubtitleProfiles>
 </Profile>

+ 3 - 1
Emby.Drawing.ImageMagick/ImageMagickEncoder.cs

@@ -44,7 +44,9 @@ namespace Emby.Drawing.ImageMagick
                     "cr2", 
                     "crw", 
                     "dng", 
-                    "nef", 
+
+                    // Remove until supported
+                    //"nef", 
                     "orf", 
                     "pef", 
                     "arw", 

+ 2 - 2
Emby.Server.Core/HttpServerFactory.cs

@@ -76,9 +76,9 @@ namespace Emby.Server.Core
 
     public class StreamFactory : IStreamFactory
     {
-        public Stream CreateNetworkStream(ISocket socket, bool ownsSocket)
+        public Stream CreateNetworkStream(IAcceptSocket acceptSocket, bool ownsSocket)
         {
-            var netSocket = (NetSocket)socket;
+            var netSocket = (NetAcceptSocket)acceptSocket;
 
             return new NetworkStream(netSocket.Socket, ownsSocket);
         }

+ 9 - 1
Emby.Server.Core/Localization/TextLocalizer.cs

@@ -39,7 +39,15 @@ namespace Emby.Server.Core.Localization
                 }
             }
 
-            return text.Normalize(form);
+            try
+            {
+                return text.Normalize(form);
+            }
+            catch (ArgumentException)
+            {
+                // if it still fails, return the original text
+                return text;
+            }
         }
 
         private static string StripInvalidUnicodeCharacters(string str)

+ 5 - 5
Emby.Server.Implementations/Data/SqliteItemRepository.cs

@@ -3388,10 +3388,10 @@ namespace Emby.Server.Implementations.Data
             var includeTypes = query.IncludeItemTypes.SelectMany(MapIncludeItemTypes).ToArray();
             if (includeTypes.Length == 1)
             {
-                whereClauses.Add("type=@type" + paramSuffix);
+                whereClauses.Add("type=@type");
                 if (statement != null)
                 {
-                    statement.TryBind("@type" + paramSuffix, includeTypes[0]);
+                    statement.TryBind("@type", includeTypes[0]);
                 }
             }
             else if (includeTypes.Length > 1)
@@ -4936,7 +4936,7 @@ namespace Emby.Server.Implementations.Data
                     ParentId = query.ParentId,
                     IsPlayed = query.IsPlayed
                 };
-                var whereClauses = GetWhereClauses(typeSubQuery, null, "itemTypes");
+                var whereClauses = GetWhereClauses(typeSubQuery, null);
 
                 whereClauses.Add("guid in (select ItemId from ItemValues where ItemValues.CleanValue=A.CleanName AND " + typeClause + ")");
 
@@ -5072,7 +5072,7 @@ namespace Emby.Server.Implementations.Data
 
                                 if (typeSubQuery != null)
                                 {
-                                    GetWhereClauses(typeSubQuery, null, "itemTypes");
+                                    GetWhereClauses(typeSubQuery, null);
                                 }
                                 BindSimilarParams(query, statement);
                                 GetWhereClauses(innerQuery, statement);
@@ -5110,7 +5110,7 @@ namespace Emby.Server.Implementations.Data
 
                                 if (typeSubQuery != null)
                                 {
-                                    GetWhereClauses(typeSubQuery, null, "itemTypes");
+                                    GetWhereClauses(typeSubQuery, null);
                                 }
                                 BindSimilarParams(query, statement);
                                 GetWhereClauses(innerQuery, statement);

+ 3 - 4
Emby.Server.Implementations/Devices/DeviceManager.cs

@@ -195,13 +195,12 @@ namespace Emby.Server.Implementations.Devices
             }
 
             var config = _config.GetUploadOptions();
-            if (!string.IsNullOrWhiteSpace(config.CameraUploadPath))
+            var path = config.CameraUploadPath;
+            if (string.IsNullOrWhiteSpace(path))
             {
-                return config.CameraUploadPath;
+                path = DefaultCameraUploadsPath;
             }
 
-            var path = DefaultCameraUploadsPath;
-
             if (config.EnableCameraUploadSubfolders)
             {
                 path = Path.Combine(path, _fileSystem.GetValidFilename(device.Name));

+ 1 - 1
Emby.Server.Implementations/Dto/DtoService.cs

@@ -491,7 +491,7 @@ namespace Emby.Server.Implementations.Dto
                 }
             }
 
-            //if (!(item is LiveTvProgram))
+            //if (!(item is LiveTvProgram) || fields.Contains(ItemFields.PlayAccess))
             {
                 dto.PlayAccess = item.GetPlayAccess(user);
             }

+ 3 - 4
Emby.Server.Implementations/Emby.Server.Implementations.csproj

@@ -104,7 +104,6 @@
     <Compile Include="HttpServer\StreamWriter.cs" />
     <Compile Include="HttpServer\SwaggerService.cs" />
     <Compile Include="Images\BaseDynamicImageProvider.cs" />
-    <Compile Include="Intros\DefaultIntroProvider.cs" />
     <Compile Include="IO\FileRefresher.cs" />
     <Compile Include="IO\MbLinkShortcutHandler.cs" />
     <Compile Include="IO\ThrottledStream.cs" />
@@ -170,9 +169,11 @@
     <Compile Include="LiveTv\RecordingImageProvider.cs" />
     <Compile Include="LiveTv\RefreshChannelsScheduledTask.cs" />
     <Compile Include="LiveTv\TunerHosts\BaseTunerHost.cs" />
+    <Compile Include="LiveTv\TunerHosts\HdHomerun\HdHomerunManager.cs" />
     <Compile Include="LiveTv\TunerHosts\HdHomerun\HdHomerunDiscovery.cs" />
     <Compile Include="LiveTv\TunerHosts\HdHomerun\HdHomerunHost.cs" />
-    <Compile Include="LiveTv\TunerHosts\HdHomerun\HdHomerunLiveStream.cs" />
+    <Compile Include="LiveTv\TunerHosts\HdHomerun\HdHomerunHttpStream.cs" />
+    <Compile Include="LiveTv\TunerHosts\HdHomerun\HdHomerunUdpStream.cs" />
     <Compile Include="LiveTv\TunerHosts\M3uParser.cs" />
     <Compile Include="LiveTv\TunerHosts\M3UTunerHost.cs" />
     <Compile Include="LiveTv\TunerHosts\MulticastStream.cs" />
@@ -238,7 +239,6 @@
     <Compile Include="Sorting\AlbumComparer.cs" />
     <Compile Include="Sorting\AlphanumComparator.cs" />
     <Compile Include="Sorting\ArtistComparer.cs" />
-    <Compile Include="Sorting\BudgetComparer.cs" />
     <Compile Include="Sorting\CommunityRatingComparer.cs" />
     <Compile Include="Sorting\CriticRatingComparer.cs" />
     <Compile Include="Sorting\DateCreatedComparer.cs" />
@@ -257,7 +257,6 @@
     <Compile Include="Sorting\PremiereDateComparer.cs" />
     <Compile Include="Sorting\ProductionYearComparer.cs" />
     <Compile Include="Sorting\RandomComparer.cs" />
-    <Compile Include="Sorting\RevenueComparer.cs" />
     <Compile Include="Sorting\RuntimeComparer.cs" />
     <Compile Include="Sorting\SeriesSortNameComparer.cs" />
     <Compile Include="Sorting\SortNameComparer.cs" />

+ 1 - 2
Emby.Server.Implementations/HttpServer/HttpListenerHost.cs

@@ -579,7 +579,7 @@ namespace Emby.Server.Implementations.HttpServer
                 }
                 else
                 {
-                    ErrorHandler(new FileNotFoundException(), httpReq);
+                    ErrorHandler(new FileNotFoundException(), httpReq, false);
                 }
             }
             catch (OperationCanceledException ex)
@@ -633,7 +633,6 @@ namespace Emby.Server.Implementations.HttpServer
             return null;
         }
 
-
         private void Write(IResponse response, string text)
         {
             var bOutput = Encoding.UTF8.GetBytes(text);

+ 0 - 394
Emby.Server.Implementations/Intros/DefaultIntroProvider.cs

@@ -1,394 +0,0 @@
-using MediaBrowser.Common.Configuration;
-using MediaBrowser.Common.Security;
-using MediaBrowser.Controller.Entities;
-using MediaBrowser.Controller.Entities.Movies;
-using MediaBrowser.Controller.Entities.TV;
-using MediaBrowser.Controller.Library;
-using MediaBrowser.Model.Configuration;
-using MediaBrowser.Model.Entities;
-using System;
-using System.Collections.Generic;
-using System.IO;
-using System.Linq;
-using System.Threading.Tasks;
-using MediaBrowser.Model.IO;
-using MediaBrowser.Model.Extensions;
-using MediaBrowser.Model.Globalization;
-
-namespace Emby.Server.Implementations.Intros
-{
-    public class DefaultIntroProvider : IIntroProvider
-    {
-        private readonly ISecurityManager _security;
-        private readonly ILocalizationManager _localization;
-        private readonly IConfigurationManager _serverConfig;
-        private readonly ILibraryManager _libraryManager;
-        private readonly IFileSystem _fileSystem;
-        private readonly IMediaSourceManager _mediaSourceManager;
-
-        public DefaultIntroProvider(ISecurityManager security, ILocalizationManager localization, IConfigurationManager serverConfig, ILibraryManager libraryManager, IFileSystem fileSystem, IMediaSourceManager mediaSourceManager)
-        {
-            _security = security;
-            _localization = localization;
-            _serverConfig = serverConfig;
-            _libraryManager = libraryManager;
-            _fileSystem = fileSystem;
-            _mediaSourceManager = mediaSourceManager;
-        }
-
-        public async Task<IEnumerable<IntroInfo>> GetIntros(BaseItem item, User user)
-        {
-            var config = GetOptions();
-
-            if (item is Movie)
-            {
-                if (!config.EnableIntrosForMovies)
-                {
-                    return new List<IntroInfo>();
-                }
-            }
-            else if (item is Episode)
-            {
-                if (!config.EnableIntrosForEpisodes)
-                {
-                    return new List<IntroInfo>();
-                }
-            }
-            else
-            {
-                return new List<IntroInfo>();
-            }
-
-            var ratingLevel = string.IsNullOrWhiteSpace(item.OfficialRating)
-                ? null
-                : _localization.GetRatingLevel(item.OfficialRating);
-
-            var candidates = new List<ItemWithTrailer>();
-
-            var trailerTypes = new List<TrailerType>();
-            var sourceTypes = new List<SourceType>();
-
-            if (config.EnableIntrosFromMoviesInLibrary)
-            {
-                trailerTypes.Add(TrailerType.LocalTrailer);
-                sourceTypes.Add(SourceType.Library);
-            }
-
-            if (IsSupporter)
-            {
-                if (config.EnableIntrosFromUpcomingTrailers)
-                {
-                    trailerTypes.Add(TrailerType.ComingSoonToTheaters);
-                    sourceTypes.Clear();
-                }
-                if (config.EnableIntrosFromUpcomingDvdMovies)
-                {
-                    trailerTypes.Add(TrailerType.ComingSoonToDvd);
-                    sourceTypes.Clear();
-                }
-                if (config.EnableIntrosFromUpcomingStreamingMovies)
-                {
-                    trailerTypes.Add(TrailerType.ComingSoonToStreaming);
-                    sourceTypes.Clear();
-                }
-                if (config.EnableIntrosFromSimilarMovies)
-                {
-                    trailerTypes.Add(TrailerType.Archive);
-                    sourceTypes.Clear();
-                }
-            }
-
-            if (trailerTypes.Count > 0)
-            {
-                if (trailerTypes.Count >= 5)
-                {
-                    trailerTypes.Clear();
-                }
-
-                // hack - can't filter by user library because local trailers get TopParentId =null in the db. 
-                // for now we have to use a post-query filter afterwards to solve that
-                var trailerResult = _libraryManager.GetItemList(new InternalItemsQuery
-                {
-                    IncludeItemTypes = new[] { typeof(Trailer).Name },
-                    TrailerTypes = trailerTypes.ToArray(),
-                    SimilarTo = item,
-                    //IsPlayed = config.EnableIntrosForWatchedContent ? (bool?)null : false,
-                    MaxParentalRating = config.EnableIntrosParentalControl ? ratingLevel : null,
-                    BlockUnratedItems = config.EnableIntrosParentalControl ? new[] { UnratedItem.Trailer } : new UnratedItem[] { },
-
-                    // Account for duplicates by imdb id, since the database doesn't support this yet
-                    Limit = config.TrailerLimit * 4,
-                    SourceTypes = sourceTypes.ToArray()
-                })
-                .Where(i => string.IsNullOrWhiteSpace(i.GetProviderId(MetadataProviders.Imdb)) || !string.Equals(i.GetProviderId(MetadataProviders.Imdb), item.GetProviderId(MetadataProviders.Imdb), StringComparison.OrdinalIgnoreCase))
-                .Where(i => i.IsVisibleStandalone(user))
-                .Where(i => config.EnableIntrosForWatchedContent || !i.IsPlayed(user))
-                .Take(config.TrailerLimit);
-
-                candidates.AddRange(trailerResult.Select(i => new ItemWithTrailer
-                {
-                    Item = i,
-                    Type = i.SourceType == SourceType.Channel ? ItemWithTrailerType.ChannelTrailer : ItemWithTrailerType.ItemWithTrailer,
-                    LibraryManager = _libraryManager
-                }));
-            }
-
-            return GetResult(item, candidates, config);
-        }
-
-        private IEnumerable<IntroInfo> GetResult(BaseItem item, IEnumerable<ItemWithTrailer> candidates, CinemaModeConfiguration config)
-        {
-            var customIntros = !string.IsNullOrWhiteSpace(config.CustomIntroPath) ?
-                GetCustomIntros(config) :
-                new List<IntroInfo>();
-
-            var mediaInfoIntros = !string.IsNullOrWhiteSpace(config.MediaInfoIntroPath) ?
-                GetMediaInfoIntros(config, item) :
-                new List<IntroInfo>();
-
-            // Avoid implicitly captured closure
-            return candidates.Select(i => i.IntroInfo)
-                .Concat(customIntros.Take(1))
-                .Concat(mediaInfoIntros);
-        }
-
-        private CinemaModeConfiguration GetOptions()
-        {
-            return _serverConfig.GetConfiguration<CinemaModeConfiguration>("cinemamode");
-        }
-
-        private List<IntroInfo> GetCustomIntros(CinemaModeConfiguration options)
-        {
-            try
-            {
-                return GetCustomIntroFiles(options, true, false)
-                    .OrderBy(i => Guid.NewGuid())
-                    .Select(i => new IntroInfo
-                    {
-                        Path = i
-
-                    }).ToList();
-            }
-            catch (IOException)
-            {
-                return new List<IntroInfo>();
-            }
-        }
-
-        private IEnumerable<IntroInfo> GetMediaInfoIntros(CinemaModeConfiguration options, BaseItem item)
-        {
-            try
-            {
-                var hasMediaSources = item as IHasMediaSources;
-
-                if (hasMediaSources == null)
-                {
-                    return new List<IntroInfo>();
-                }
-
-                var mediaSource = _mediaSourceManager.GetStaticMediaSources(hasMediaSources, false)
-                    .FirstOrDefault();
-
-                if (mediaSource == null)
-                {
-                    return new List<IntroInfo>();
-                }
-
-                var videoStream = mediaSource.MediaStreams.FirstOrDefault(i => i.Type == MediaStreamType.Video);
-                var audioStream = mediaSource.MediaStreams.FirstOrDefault(i => i.Type == MediaStreamType.Audio);
-
-                var allIntros = GetCustomIntroFiles(options, false, true)
-                    .OrderBy(i => Guid.NewGuid())
-                    .Select(i => new IntroInfo
-                    {
-                        Path = i
-
-                    }).ToList();
-
-                var returnResult = new List<IntroInfo>();
-
-                if (videoStream != null)
-                {
-                    returnResult.AddRange(GetMediaInfoIntrosByVideoStream(allIntros, videoStream).Take(1));
-                }
-
-                if (audioStream != null)
-                {
-                    returnResult.AddRange(GetMediaInfoIntrosByAudioStream(allIntros, audioStream).Take(1));
-                }
-
-                returnResult.AddRange(GetMediaInfoIntrosByTags(allIntros, item.Tags).Take(1));
-
-                return returnResult.DistinctBy(i => i.Path, StringComparer.OrdinalIgnoreCase);
-            }
-            catch (IOException)
-            {
-                return new List<IntroInfo>();
-            }
-        }
-
-        private IEnumerable<IntroInfo> GetMediaInfoIntrosByVideoStream(List<IntroInfo> allIntros, MediaStream stream)
-        {
-            var codec = stream.Codec;
-
-            if (string.IsNullOrWhiteSpace(codec))
-            {
-                return new List<IntroInfo>();
-            }
-
-            return allIntros
-                .Where(i => IsMatch(i.Path, codec))
-                .OrderBy(i => Guid.NewGuid());
-        }
-
-        private IEnumerable<IntroInfo> GetMediaInfoIntrosByAudioStream(List<IntroInfo> allIntros, MediaStream stream)
-        {
-            var codec = stream.Codec;
-
-            if (string.IsNullOrWhiteSpace(codec))
-            {
-                return new List<IntroInfo>();
-            }
-
-            return allIntros
-                .Where(i => IsAudioMatch(i.Path, stream))
-                .OrderBy(i => Guid.NewGuid());
-        }
-
-        private IEnumerable<IntroInfo> GetMediaInfoIntrosByTags(List<IntroInfo> allIntros, List<string> tags)
-        {
-            return allIntros
-                .Where(i => tags.Any(t => IsMatch(i.Path, t)))
-                .OrderBy(i => Guid.NewGuid());
-        }
-
-        private bool IsMatch(string file, string attribute)
-        {
-            var filename = Path.GetFileNameWithoutExtension(file) ?? string.Empty;
-            filename = Normalize(filename);
-
-            if (string.IsNullOrWhiteSpace(filename))
-            {
-                return false;
-            }
-
-            attribute = Normalize(attribute);
-            if (string.IsNullOrWhiteSpace(attribute))
-            {
-                return false;
-            }
-
-            return string.Equals(filename, attribute, StringComparison.OrdinalIgnoreCase);
-        }
-
-        private string Normalize(string value)
-        {
-            return value;
-        }
-
-        private bool IsAudioMatch(string path, MediaStream stream)
-        {
-            if (!string.IsNullOrWhiteSpace(stream.Codec))
-            {
-                if (IsMatch(path, stream.Codec))
-                {
-                    return true;
-                }
-            }
-            if (!string.IsNullOrWhiteSpace(stream.Profile))
-            {
-                if (IsMatch(path, stream.Profile))
-                {
-                    return true;
-                }
-            }
-
-            return false;
-        }
-
-        private IEnumerable<string> GetCustomIntroFiles(CinemaModeConfiguration options, bool enableCustomIntros, bool enableMediaInfoIntros)
-        {
-            var list = new List<string>();
-
-            if (enableCustomIntros && !string.IsNullOrWhiteSpace(options.CustomIntroPath))
-            {
-                list.AddRange(_fileSystem.GetFilePaths(options.CustomIntroPath, true)
-                    .Where(_libraryManager.IsVideoFile));
-            }
-
-            if (enableMediaInfoIntros && !string.IsNullOrWhiteSpace(options.MediaInfoIntroPath))
-            {
-                list.AddRange(_fileSystem.GetFilePaths(options.MediaInfoIntroPath, true)
-                    .Where(_libraryManager.IsVideoFile));
-            }
-
-            return list.Distinct(StringComparer.OrdinalIgnoreCase);
-        }
-
-        public IEnumerable<string> GetAllIntroFiles()
-        {
-            return GetCustomIntroFiles(GetOptions(), true, true);
-        }
-
-        private bool IsSupporter
-        {
-            get { return _security.IsMBSupporter; }
-        }
-
-        public string Name
-        {
-            get { return "Default"; }
-        }
-
-        internal class ItemWithTrailer
-        {
-            internal BaseItem Item;
-            internal ItemWithTrailerType Type;
-            internal ILibraryManager LibraryManager;
-
-            public IntroInfo IntroInfo
-            {
-                get
-                {
-                    var id = Item.Id;
-
-                    if (Type == ItemWithTrailerType.ItemWithTrailer)
-                    {
-                        var hasTrailers = Item as IHasTrailers;
-
-                        if (hasTrailers != null)
-                        {
-                            id = hasTrailers.LocalTrailerIds.FirstOrDefault();
-                        }
-                    }
-                    return new IntroInfo
-                    {
-                        ItemId = id
-                    };
-                }
-            }
-        }
-
-        internal enum ItemWithTrailerType
-        {
-            ChannelTrailer,
-            ItemWithTrailer
-        }
-    }
-
-    public class CinemaModeConfigurationFactory : IConfigurationFactory
-    {
-        public IEnumerable<ConfigurationStore> GetConfigurations()
-        {
-            return new[]
-            {
-                new ConfigurationStore
-                {
-                     ConfigurationType = typeof(CinemaModeConfiguration),
-                     Key = "cinemamode"
-                }
-            };
-        }
-    }
-
-}

+ 30 - 8
Emby.Server.Implementations/Library/LibraryManager.cs

@@ -409,24 +409,46 @@ namespace Emby.Server.Implementations.Library
 
             if (options.DeleteFileLocation && locationType != LocationType.Remote && locationType != LocationType.Virtual)
             {
+                // Assume only the first is required
+                // Add this flag to GetDeletePaths if required in the future
+                var isRequiredForDelete = true;
+
                 foreach (var fileSystemInfo in item.GetDeletePaths().ToList())
                 {
-                    if (fileSystemInfo.IsDirectory)
+                    try
                     {
-                        _logger.Debug("Deleting path {0}", fileSystemInfo.FullName);
-                        _fileSystem.DeleteDirectory(fileSystemInfo.FullName, true);
+                        if (fileSystemInfo.IsDirectory)
+                        {
+                            _logger.Debug("Deleting path {0}", fileSystemInfo.FullName);
+                            _fileSystem.DeleteDirectory(fileSystemInfo.FullName, true);
+                        }
+                        else
+                        {
+                            _logger.Debug("Deleting path {0}", fileSystemInfo.FullName);
+                            _fileSystem.DeleteFile(fileSystemInfo.FullName);
+                        }
                     }
-                    else
+                    catch (IOException)
                     {
-                        _logger.Debug("Deleting path {0}", fileSystemInfo.FullName);
-                        _fileSystem.DeleteFile(fileSystemInfo.FullName);
+                        if (isRequiredForDelete)
+                        {
+                            throw;
+                        }
                     }
+                    catch (UnauthorizedAccessException)
+                    {
+                        if (isRequiredForDelete)
+                        {
+                            throw;
+                        }
+                    }
+
+                    isRequiredForDelete = false;
                 }
 
                 if (parent != null)
                 {
-                    await parent.ValidateChildren(new Progress<double>(), CancellationToken.None)
-                              .ConfigureAwait(false);
+                    await parent.ValidateChildren(new Progress<double>(), CancellationToken.None, new MetadataRefreshOptions(_fileSystem), false) .ConfigureAwait(false);
                 }
             }
             else if (parent != null)

+ 5 - 0
Emby.Server.Implementations/Library/UserManager.cs

@@ -434,6 +434,11 @@ namespace Emby.Server.Implementations.Library
                 Policy = user.Policy
             };
 
+            if (!hasPassword && Users.Count() == 1)
+            {
+                dto.EnableAutoLogin = true;
+            }
+
             var image = user.GetImageInfo(ImageType.Primary, 0);
 
             if (image != null)

+ 11 - 1
Emby.Server.Implementations/LiveTv/Listings/SchedulesDirect.cs

@@ -282,6 +282,12 @@ namespace Emby.Server.Implementations.LiveTv.Listings
 
             var showId = programInfo.programID ?? string.Empty;
 
+            if (!info.IsSeries)
+            {
+                // It's also a series if it starts with SH
+                info.IsSeries = showId.StartsWith("SH", StringComparison.OrdinalIgnoreCase) && showId.Length >= 14;
+            }
+
             // According to SchedulesDirect, these are generic, unidentified episodes
             // SH005316560000
             var hasUniqueShowId = !showId.StartsWith("SH", StringComparison.OrdinalIgnoreCase) ||
@@ -331,7 +337,11 @@ namespace Emby.Server.Implementations.LiveTv.Listings
                 {
                     var gracenote = details.metadata.Find(x => x.Gracenote != null).Gracenote;
                     info.SeasonNumber = gracenote.season;
-                    info.EpisodeNumber = gracenote.episode;
+
+                    if (gracenote.episode > 0)
+                    {
+                        info.EpisodeNumber = gracenote.episode;
+                    }
                 }
             }
 

+ 5 - 2
Emby.Server.Implementations/LiveTv/LiveStreamHelper.cs

@@ -6,7 +6,6 @@ using System.Threading.Tasks;
 using MediaBrowser.Controller.MediaEncoding;
 using MediaBrowser.Model.Dlna;
 using MediaBrowser.Model.Dto;
-using MediaBrowser.Model.Entities;
 using MediaBrowser.Model.Logging;
 
 namespace Emby.Server.Implementations.LiveTv
@@ -16,6 +15,8 @@ namespace Emby.Server.Implementations.LiveTv
         private readonly IMediaEncoder _mediaEncoder;
         private readonly ILogger _logger;
 
+        const int AnalyzeDurationMs = 2000;
+
         public LiveStreamHelper(IMediaEncoder mediaEncoder, ILogger logger)
         {
             _mediaEncoder = mediaEncoder;
@@ -34,7 +35,7 @@ namespace Emby.Server.Implementations.LiveTv
                 Protocol = mediaSource.Protocol,
                 MediaType = isAudio ? DlnaProfileType.Audio : DlnaProfileType.Video,
                 ExtractChapters = false,
-                AnalyzeDurationSections = 2
+                AnalyzeDurationMs = AnalyzeDurationMs
 
             }, cancellationToken).ConfigureAwait(false);
 
@@ -98,6 +99,8 @@ namespace Emby.Server.Implementations.LiveTv
 
             // Try to estimate this
             mediaSource.InferTotalBitrate(true);
+
+            mediaSource.AnalyzeDurationMs = AnalyzeDurationMs;
         }
     }
 }

+ 1 - 0
Emby.Server.Implementations/LiveTv/LiveTvManager.cs

@@ -1596,6 +1596,7 @@ namespace Emby.Server.Implementations.LiveTv
                 IsFolder = false,
                 IsVirtualItem = false,
                 Limit = query.Limit,
+                StartIndex = query.StartIndex,
                 SortBy = new[] { ItemSortBy.DateCreated },
                 SortOrder = SortOrder.Descending,
                 EnableTotalRecordCount = query.EnableTotalRecordCount,

+ 198 - 120
Emby.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunHost.cs

@@ -28,13 +28,17 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts.HdHomerun
         private readonly IHttpClient _httpClient;
         private readonly IFileSystem _fileSystem;
         private readonly IServerApplicationHost _appHost;
+        private readonly ISocketFactory _socketFactory;
+        private readonly INetworkManager _networkManager;
 
-        public HdHomerunHost(IServerConfigurationManager config, ILogger logger, IJsonSerializer jsonSerializer, IMediaEncoder mediaEncoder, IHttpClient httpClient, IFileSystem fileSystem, IServerApplicationHost appHost)
+        public HdHomerunHost(IServerConfigurationManager config, ILogger logger, IJsonSerializer jsonSerializer, IMediaEncoder mediaEncoder, IHttpClient httpClient, IFileSystem fileSystem, IServerApplicationHost appHost, ISocketFactory socketFactory, INetworkManager networkManager)
             : base(config, logger, jsonSerializer, mediaEncoder)
         {
             _httpClient = httpClient;
             _fileSystem = fileSystem;
             _appHost = appHost;
+            _socketFactory = socketFactory;
+            _networkManager = networkManager;
         }
 
         public string Name
@@ -65,9 +69,11 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts.HdHomerun
 
         private async Task<List<Channels>> GetLineup(TunerHostInfo info, CancellationToken cancellationToken)
         {
+            var model = await GetModelInfo(info, false, cancellationToken).ConfigureAwait(false);
+
             var options = new HttpRequestOptions
             {
-                Url = string.Format("{0}/lineup.json", GetApiUrl(info, false)),
+                Url = model.LineupURL,
                 CancellationToken = cancellationToken,
                 BufferContent = false
             };
@@ -84,11 +90,17 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts.HdHomerun
             }
         }
 
+        private class HdHomerunChannelInfo : ChannelInfo
+        {
+            public bool IsLegacyTuner { get; set; }
+            public string Url { get; set; }
+        }
+
         protected override async Task<List<ChannelInfo>> GetChannelsInternal(TunerHostInfo info, CancellationToken cancellationToken)
         {
             var lineup = await GetLineup(info, cancellationToken).ConfigureAwait(false);
 
-            return lineup.Select(i => new ChannelInfo
+            return lineup.Select(i => new HdHomerunChannelInfo
             {
                 Name = i.GuideName,
                 Number = i.GuideNumber,
@@ -98,20 +110,22 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts.HdHomerun
                 IsHD = i.HD == 1,
                 AudioCodec = i.AudioCodec,
                 VideoCodec = i.VideoCodec,
-                ChannelType = ChannelType.TV
+                ChannelType = ChannelType.TV,
+                IsLegacyTuner = (i.URL ?? string.Empty).StartsWith("hdhomerun", StringComparison.OrdinalIgnoreCase),
+                Url = i.URL
 
-            }).ToList();
+            }).Cast<ChannelInfo>().ToList();
         }
 
         private readonly Dictionary<string, DiscoverResponse> _modelCache = new Dictionary<string, DiscoverResponse>();
-        private async Task<string> GetModelInfo(TunerHostInfo info, CancellationToken cancellationToken)
+        private async Task<DiscoverResponse> GetModelInfo(TunerHostInfo info, bool throwAllExceptions, CancellationToken cancellationToken)
         {
             lock (_modelCache)
             {
                 DiscoverResponse response;
                 if (_modelCache.TryGetValue(info.Url, out response))
                 {
-                    return response.ModelNumber;
+                    return response;
                 }
             }
 
@@ -130,72 +144,70 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts.HdHomerun
                 {
                     var response = JsonSerializer.DeserializeFromStream<DiscoverResponse>(stream);
 
-                    lock (_modelCache)
+                    if (!string.IsNullOrWhiteSpace(info.Id))
                     {
-                        _modelCache[info.Id] = response;
+                        lock (_modelCache)
+                        {
+                            _modelCache[info.Id] = response;
+                        }
                     }
 
-                    return response.ModelNumber;
+                    return response;
                 }
             }
             catch (HttpException ex)
             {
-                if (ex.StatusCode.HasValue && ex.StatusCode.Value == System.Net.HttpStatusCode.NotFound)
+                if (!throwAllExceptions && ex.StatusCode.HasValue && ex.StatusCode.Value == System.Net.HttpStatusCode.NotFound)
                 {
                     var defaultValue = "HDHR";
-                    // HDHR4 doesn't have this api
-                    lock (_modelCache)
+                    var response = new DiscoverResponse
+                    {
+                        ModelNumber = defaultValue
+                    };
+                    if (!string.IsNullOrWhiteSpace(info.Id))
                     {
-                        _modelCache[info.Id] = new DiscoverResponse
+                        // HDHR4 doesn't have this api
+                        lock (_modelCache)
                         {
-                            ModelNumber = defaultValue
-                        };
+                            _modelCache[info.Id] = response;
+                        }
                     }
-                    return defaultValue;
+                    return response;
                 }
 
                 throw;
             }
         }
 
-        public async Task<List<LiveTvTunerInfo>> GetTunerInfos(TunerHostInfo info, CancellationToken cancellationToken)
+        private async Task<List<LiveTvTunerInfo>> GetTunerInfos(TunerHostInfo info, CancellationToken cancellationToken)
         {
-            var model = await GetModelInfo(info, cancellationToken).ConfigureAwait(false);
+            var model = await GetModelInfo(info, false, cancellationToken).ConfigureAwait(false);
 
-            using (var stream = await _httpClient.Get(new HttpRequestOptions()
-            {
-                Url = string.Format("{0}/tuners.html", GetApiUrl(info, false)),
-                CancellationToken = cancellationToken,
-                TimeoutMs = Convert.ToInt32(TimeSpan.FromSeconds(5).TotalMilliseconds),
-                BufferContent = false
+            var tuners = new List<LiveTvTunerInfo>();
+
+            var uri = new Uri(GetApiUrl(info, false));
 
-            }).ConfigureAwait(false))
+            using (var manager = new HdHomerunManager(_socketFactory))
             {
-                var tuners = new List<LiveTvTunerInfo>();
-                using (var sr = new StreamReader(stream, System.Text.Encoding.UTF8))
+                // Legacy HdHomeruns are IPv4 only
+                var ipInfo = _networkManager.ParseIpAddress(uri.Host);
+
+                for (int i = 0; i < model.TunerCount; ++i)
                 {
-                    while (!sr.EndOfStream)
+                    var name = String.Format("Tuner {0}", i + 1);
+                    var currentChannel = "none"; /// @todo Get current channel and map back to Station Id      
+                    var isAvailable = await manager.CheckTunerAvailability(ipInfo, i, cancellationToken).ConfigureAwait(false);
+                    LiveTvTunerStatus status = isAvailable ? LiveTvTunerStatus.Available : LiveTvTunerStatus.LiveTv;
+                    tuners.Add(new LiveTvTunerInfo
                     {
-                        string line = StripXML(sr.ReadLine());
-                        if (line.Contains("Channel"))
-                        {
-                            LiveTvTunerStatus status;
-                            var index = line.IndexOf("Channel", StringComparison.OrdinalIgnoreCase);
-                            var name = line.Substring(0, index - 1);
-                            var currentChannel = line.Substring(index + 7);
-                            if (currentChannel != "none") { status = LiveTvTunerStatus.LiveTv; } else { status = LiveTvTunerStatus.Available; }
-                            tuners.Add(new LiveTvTunerInfo
-                            {
-                                Name = name,
-                                SourceType = string.IsNullOrWhiteSpace(model) ? Name : model,
-                                ProgramName = currentChannel,
-                                Status = status
-                            });
-                        }
-                    }
+                        Name = name,
+                        SourceType = string.IsNullOrWhiteSpace(model.ModelNumber) ? Name : model.ModelNumber,
+                        ProgramName = currentChannel,
+                        Status = status
+                    });
                 }
-                return tuners;
             }
+            return tuners;
         }
 
         public async Task<List<LiveTvTunerInfo>> GetTunerInfos(CancellationToken cancellationToken)
@@ -244,34 +256,6 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts.HdHomerun
             return uri.AbsoluteUri.TrimEnd('/');
         }
 
-        private static string StripXML(string source)
-        {
-            char[] buffer = new char[source.Length];
-            int bufferIndex = 0;
-            bool inside = false;
-
-            for (int i = 0; i < source.Length; i++)
-            {
-                char let = source[i];
-                if (let == '<')
-                {
-                    inside = true;
-                    continue;
-                }
-                if (let == '>')
-                {
-                    inside = false;
-                    continue;
-                }
-                if (!inside)
-                {
-                    buffer[bufferIndex] = let;
-                    bufferIndex++;
-                }
-            }
-            return new string(buffer, 0, bufferIndex);
-        }
-
         private class Channels
         {
             public string GuideNumber { get; set; }
@@ -284,13 +268,13 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts.HdHomerun
             public int HD { get; set; }
         }
 
-        private async Task<MediaSourceInfo> GetMediaSource(TunerHostInfo info, string channelId, string profile)
+        private MediaSourceInfo GetMediaSource(TunerHostInfo info, string channelId, ChannelInfo channelInfo, string profile)
         {
             int? width = null;
             int? height = null;
             bool isInterlaced = true;
             string videoCodec = null;
-            string audioCodec = "ac3";
+            string audioCodec = null;
 
             int? videoBitrate = null;
             int? audioBitrate = null;
@@ -344,21 +328,19 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts.HdHomerun
                 videoBitrate = 1000000;
             }
 
-            var channels = await GetChannels(info, true, CancellationToken.None).ConfigureAwait(false);
-            var channel = channels.FirstOrDefault(i => string.Equals(i.Number, channelId, StringComparison.OrdinalIgnoreCase));
-            if (channel != null)
+            if (channelInfo != null)
             {
                 if (string.IsNullOrWhiteSpace(videoCodec))
                 {
-                    videoCodec = channel.VideoCodec;
+                    videoCodec = channelInfo.VideoCodec;
                 }
-                audioCodec = channel.AudioCodec;
+                audioCodec = channelInfo.AudioCodec;
 
                 if (!videoBitrate.HasValue)
                 {
-                    videoBitrate = (channel.IsHD ?? true) ? 15000000 : 2000000;
+                    videoBitrate = (channelInfo.IsHD ?? true) ? 15000000 : 2000000;
                 }
-                audioBitrate = (channel.IsHD ?? true) ? 448000 : 192000;
+                audioBitrate = (channelInfo.IsHD ?? true) ? 448000 : 192000;
             }
 
             // normalize
@@ -443,6 +425,82 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts.HdHomerun
             return channelId.Split('_')[1];
         }
 
+        private MediaSourceInfo GetLegacyMediaSource(TunerHostInfo info, string channelId, ChannelInfo channel)
+        {
+            int? width = null;
+            int? height = null;
+            bool isInterlaced = true;
+            string videoCodec = null;
+            string audioCodec = null;
+
+            int? videoBitrate = null;
+            int? audioBitrate = null;
+
+            if (channel != null)
+            {
+                if (string.IsNullOrWhiteSpace(videoCodec))
+                {
+                    videoCodec = channel.VideoCodec;
+                }
+                audioCodec = channel.AudioCodec;
+            }
+
+            // normalize
+            if (string.Equals(videoCodec, "mpeg2", StringComparison.OrdinalIgnoreCase))
+            {
+                videoCodec = "mpeg2video";
+            }
+
+            string nal = null;
+
+            var url = GetApiUrl(info, false);
+            var id = channelId;
+            id += "_" + url.GetMD5().ToString("N");
+
+            var mediaSource = new MediaSourceInfo
+            {
+                Path = url,
+                Protocol = MediaProtocol.Udp,
+                MediaStreams = new List<MediaStream>
+                        {
+                            new MediaStream
+                            {
+                                Type = MediaStreamType.Video,
+                                // Set the index to -1 because we don't know the exact index of the video stream within the container
+                                Index = -1,
+                                IsInterlaced = isInterlaced,
+                                Codec = videoCodec,
+                                Width = width,
+                                Height = height,
+                                BitRate = videoBitrate,
+                                NalLengthSize = nal
+
+                            },
+                            new MediaStream
+                            {
+                                Type = MediaStreamType.Audio,
+                                // Set the index to -1 because we don't know the exact index of the audio stream within the container
+                                Index = -1,
+                                Codec = audioCodec,
+                                BitRate = audioBitrate
+                            }
+                        },
+                RequiresOpening = true,
+                RequiresClosing = true,
+                BufferMs = 0,
+                Container = "ts",
+                Id = id,
+                SupportsDirectPlay = false,
+                SupportsDirectStream = true,
+                SupportsTranscoding = true,
+                IsInfiniteStream = true
+            };
+
+            mediaSource.InferTotalBitrate();
+
+            return mediaSource;
+        }
+
         protected override async Task<List<MediaSourceInfo>> GetChannelStreamMediaSources(TunerHostInfo info, string channelId, CancellationToken cancellationToken)
         {
             var list = new List<MediaSourceInfo>();
@@ -453,35 +511,49 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts.HdHomerun
             }
             var hdhrId = GetHdHrIdFromChannelId(channelId);
 
-            try
-            {
-                var model = await GetModelInfo(info, cancellationToken).ConfigureAwait(false);
-                model = model ?? string.Empty;
+            var channels = await GetChannels(info, true, CancellationToken.None).ConfigureAwait(false);
+            var channelInfo = channels.FirstOrDefault(i => string.Equals(i.Id, channelId, StringComparison.OrdinalIgnoreCase));
+
+            var hdHomerunChannelInfo = channelInfo as HdHomerunChannelInfo;
 
-                if ((model.IndexOf("hdtc", StringComparison.OrdinalIgnoreCase) != -1))
+            var isLegacyTuner = hdHomerunChannelInfo != null && hdHomerunChannelInfo.IsLegacyTuner;
+
+            if (isLegacyTuner)
+            {
+                list.Add(GetLegacyMediaSource(info, hdhrId, channelInfo));
+            }
+            else
+            {
+                try
                 {
-                    list.Add(await GetMediaSource(info, hdhrId, "native").ConfigureAwait(false));
+                    var modelInfo = await GetModelInfo(info, false, cancellationToken).ConfigureAwait(false);
+                    var model = modelInfo == null ? string.Empty : (modelInfo.ModelNumber ?? string.Empty);
 
-                    if (info.AllowHWTranscoding)
+                    if ((model.IndexOf("hdtc", StringComparison.OrdinalIgnoreCase) != -1))
                     {
-                        list.Add(await GetMediaSource(info, hdhrId, "heavy").ConfigureAwait(false));
+                        list.Add(GetMediaSource(info, hdhrId, channelInfo, "native"));
+
+                        if (info.AllowHWTranscoding)
+                        {
+                            list.Add(GetMediaSource(info, hdhrId, channelInfo, "heavy"));
 
-                        list.Add(await GetMediaSource(info, hdhrId, "internet540").ConfigureAwait(false));
-                        list.Add(await GetMediaSource(info, hdhrId, "internet480").ConfigureAwait(false));
-                        list.Add(await GetMediaSource(info, hdhrId, "internet360").ConfigureAwait(false));
-                        list.Add(await GetMediaSource(info, hdhrId, "internet240").ConfigureAwait(false));
-                        list.Add(await GetMediaSource(info, hdhrId, "mobile").ConfigureAwait(false));
+                            list.Add(GetMediaSource(info, hdhrId, channelInfo, "internet540"));
+                            list.Add(GetMediaSource(info, hdhrId, channelInfo, "internet480"));
+                            list.Add(GetMediaSource(info, hdhrId, channelInfo, "internet360"));
+                            list.Add(GetMediaSource(info, hdhrId, channelInfo, "internet240"));
+                            list.Add(GetMediaSource(info, hdhrId, channelInfo, "mobile"));
+                        }
                     }
                 }
-            }
-            catch
-            {
+                catch
+                {
 
-            }
+                }
 
-            if (list.Count == 0)
-            {
-                list.Add(await GetMediaSource(info, hdhrId, "native").ConfigureAwait(false));
+                if (list.Count == 0)
+                {
+                    list.Add(GetMediaSource(info, hdhrId, channelInfo, "native"));
+                }
             }
 
             return list;
@@ -509,11 +581,26 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts.HdHomerun
             }
             var hdhrId = GetHdHrIdFromChannelId(channelId);
 
-            var mediaSource = await GetMediaSource(info, hdhrId, profile).ConfigureAwait(false);
+            var channels = await GetChannels(info, true, CancellationToken.None).ConfigureAwait(false);
+            var channelInfo = channels.FirstOrDefault(i => string.Equals(i.Id, channelId, StringComparison.OrdinalIgnoreCase));
+
+            var hdhomerunChannel = channelInfo as HdHomerunChannelInfo;
 
-            var liveStream = new HdHomerunLiveStream(mediaSource, streamId, _fileSystem, _httpClient, Logger, Config.ApplicationPaths, _appHost);
-            liveStream.EnableStreamSharing = true;
-            return liveStream;
+            if (hdhomerunChannel != null && hdhomerunChannel.IsLegacyTuner)
+            {              
+                var mediaSource = GetLegacyMediaSource(info, hdhrId, channelInfo);
+                var modelInfo = await GetModelInfo(info, false, cancellationToken).ConfigureAwait(false);
+
+                return new HdHomerunUdpStream(mediaSource, streamId, new LegacyHdHomerunChannelCommands(hdhomerunChannel.Url), modelInfo.TunerCount, _fileSystem, _httpClient, Logger, Config.ApplicationPaths, _appHost, _socketFactory, _networkManager);
+            }
+            else
+            {
+                var mediaSource = GetMediaSource(info, hdhrId, channelInfo, profile);
+                //var modelInfo = await GetModelInfo(info, false, cancellationToken).ConfigureAwait(false);
+
+                return new HdHomerunHttpStream(mediaSource, streamId, _fileSystem, _httpClient, Logger, Config.ApplicationPaths, _appHost);
+                //return new HdHomerunUdpStream(mediaSource, streamId, new HdHomerunChannelCommands(hdhomerunChannel.Number), modelInfo.TunerCount, _fileSystem, _httpClient, Logger, Config.ApplicationPaths, _appHost, _socketFactory, _networkManager);
+            }
         }
 
         public async Task Validate(TunerHostInfo info)
@@ -531,18 +618,8 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts.HdHomerun
             try
             {
                 // Test it by pulling down the lineup
-                using (var stream = await _httpClient.Get(new HttpRequestOptions
-                {
-                    Url = string.Format("{0}/discover.json", GetApiUrl(info, false)),
-                    CancellationToken = CancellationToken.None,
-                    BufferContent = false
-
-                }).ConfigureAwait(false))
-                {
-                    var response = JsonSerializer.DeserializeFromStream<DiscoverResponse>(stream);
-
-                    info.DeviceId = response.DeviceID;
-                }
+                var modelInfo = await GetModelInfo(info, true, CancellationToken.None).ConfigureAwait(false);
+                info.DeviceId = modelInfo.DeviceID;
             }
             catch (HttpException ex)
             {
@@ -573,6 +650,7 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts.HdHomerun
             public string DeviceAuth { get; set; }
             public string BaseURL { get; set; }
             public string LineupURL { get; set; }
+            public int TunerCount { get; set; }
         }
     }
 }

+ 2 - 2
Emby.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunLiveStream.cs → Emby.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunHttpStream.cs

@@ -13,7 +13,7 @@ using MediaBrowser.Model.MediaInfo;
 
 namespace Emby.Server.Implementations.LiveTv.TunerHosts.HdHomerun
 {
-    public class HdHomerunLiveStream : LiveStream, IDirectStreamProvider
+    public class HdHomerunHttpStream : LiveStream, IDirectStreamProvider
     {
         private readonly ILogger _logger;
         private readonly IHttpClient _httpClient;
@@ -25,7 +25,7 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts.HdHomerun
         private readonly TaskCompletionSource<bool> _liveStreamTaskCompletionSource = new TaskCompletionSource<bool>();
         private readonly MulticastStream _multicastStream;
 
-        public HdHomerunLiveStream(MediaSourceInfo mediaSource, string originalStreamId, IFileSystem fileSystem, IHttpClient httpClient, ILogger logger, IServerApplicationPaths appPaths, IServerApplicationHost appHost)
+        public HdHomerunHttpStream(MediaSourceInfo mediaSource, string originalStreamId, IFileSystem fileSystem, IHttpClient httpClient, ILogger logger, IServerApplicationPaths appPaths, IServerApplicationHost appHost)
             : base(mediaSource)
         {
             _fileSystem = fileSystem;

+ 453 - 0
Emby.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunManager.cs

@@ -0,0 +1,453 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Text.RegularExpressions;
+using System.Threading;
+using System.Threading.Tasks;
+using MediaBrowser.Model.Net;
+
+namespace Emby.Server.Implementations.LiveTv.TunerHosts.HdHomerun
+{
+    public interface IHdHomerunChannelCommands
+    {
+        IEnumerable<Tuple<string, string>> GetCommands();
+    }
+
+    public class LegacyHdHomerunChannelCommands : IHdHomerunChannelCommands
+    {
+        private string _channel;
+        private string _program;
+        public LegacyHdHomerunChannelCommands(string url)
+        {
+            // parse url for channel and program
+            var regExp = new Regex(@"\/ch(\d+)-?(\d*)");
+            var match = regExp.Match(url);
+            if (match.Success)
+            {
+                _channel = match.Groups[1].Value;
+                _program = match.Groups[2].Value;
+            }
+        }
+
+        public IEnumerable<Tuple<string, string>> GetCommands()
+        {
+            var commands = new List<Tuple<string, string>>();
+
+            if (!String.IsNullOrEmpty(_channel))
+                commands.Add(Tuple.Create("channel", _channel));
+
+            if (!String.IsNullOrEmpty(_program))
+                commands.Add(Tuple.Create("program", _program));
+            return commands;
+        }
+    }
+
+    public class HdHomerunChannelCommands : IHdHomerunChannelCommands
+    {
+        private string _channel;
+
+        public HdHomerunChannelCommands(string channel)
+        {
+            _channel = channel;
+        }
+
+        public IEnumerable<Tuple<string, string>> GetCommands()
+        {
+            var commands = new List<Tuple<string, string>>();
+
+            if (!String.IsNullOrEmpty(_channel))
+                commands.Add(Tuple.Create("vchannel", _channel));
+
+            return commands;
+        }
+    }
+
+    public class HdHomerunManager : IDisposable
+    {
+        public static int HdHomeRunPort = 65001;
+        // Message constants
+        private static byte GetSetName = 3;
+        private static byte GetSetValue = 4;
+        private static byte GetSetLockkey = 21;
+        private static ushort GetSetRequest = 4;
+        private static ushort GetSetReply = 5;
+
+        private uint? _lockkey = null;
+        private int _activeTuner = 0;
+        private readonly ISocketFactory _socketFactory;
+        private IpAddressInfo _remoteIp;
+
+        public HdHomerunManager(ISocketFactory socketFactory)
+        {
+            _socketFactory = socketFactory;
+        }
+
+        public void Dispose()
+        {
+            var task = StopStreaming();
+
+            Task.WaitAll(task);
+        }
+
+        public async Task<bool> CheckTunerAvailability(IpAddressInfo remoteIp, int tuner, CancellationToken cancellationToken)
+        {
+            using (var socket = _socketFactory.CreateTcpSocket(remoteIp, HdHomeRunPort))
+            {
+                return await CheckTunerAvailability(socket, remoteIp, tuner, cancellationToken).ConfigureAwait(false);
+            }
+        }
+
+        private async Task<bool> CheckTunerAvailability(ISocket socket, IpAddressInfo remoteIp, int tuner, CancellationToken cancellationToken)
+        {
+            var ipEndPoint = new IpEndPointInfo(remoteIp, HdHomeRunPort);
+
+            var lockkeyMsg = CreateGetMessage(tuner, "lockkey");
+            await socket.SendAsync(lockkeyMsg, lockkeyMsg.Length, ipEndPoint, cancellationToken);
+            var response = await socket.ReceiveAsync(cancellationToken).ConfigureAwait(false);
+            string returnVal;
+            ParseReturnMessage(response.Buffer, response.ReceivedBytes, out returnVal);
+
+            return string.Equals(returnVal, "none", StringComparison.OrdinalIgnoreCase);
+        }
+
+        public async Task StartStreaming(IpAddressInfo remoteIp, IpAddressInfo localIp, int localPort, IHdHomerunChannelCommands commands, int numTuners, CancellationToken cancellationToken)
+        {
+            _remoteIp = remoteIp;
+            
+            using (var tcpClient = _socketFactory.CreateTcpSocket(_remoteIp, HdHomeRunPort))
+            {
+                if (!_lockkey.HasValue)
+                {
+                    var rand = new Random();
+                    _lockkey = (uint)rand.Next();
+                }
+
+                var ipEndPoint = new IpEndPointInfo(_remoteIp, HdHomeRunPort);
+
+                for (int i = 0; i < numTuners; ++i)
+                {
+                    if (!await CheckTunerAvailability(tcpClient, _remoteIp, i, cancellationToken).ConfigureAwait(false))
+                        continue;
+
+                    _activeTuner = i;
+                    var lockKeyString = String.Format("{0:d}", _lockkey.Value);
+                    var lockkeyMsg = CreateSetMessage(i, "lockkey", lockKeyString, null);
+                    await tcpClient.SendAsync(lockkeyMsg, lockkeyMsg.Length, ipEndPoint, cancellationToken).ConfigureAwait(false);
+                    var response = await tcpClient.ReceiveAsync(cancellationToken).ConfigureAwait(false);
+                    string returnVal;
+                    // parse response to make sure it worked
+                    if (!ParseReturnMessage(response.Buffer, response.ReceivedBytes, out returnVal))
+                        continue;
+
+                    var commandList = commands.GetCommands();
+                    foreach(Tuple<string,string> command in commandList)
+                    {
+                        var channelMsg = CreateSetMessage(i, command.Item1, command.Item2, _lockkey.Value);
+                        await tcpClient.SendAsync(channelMsg, channelMsg.Length, ipEndPoint, cancellationToken).ConfigureAwait(false);
+                        response = await tcpClient.ReceiveAsync(cancellationToken).ConfigureAwait(false);
+                        // parse response to make sure it worked
+                        if (!ParseReturnMessage(response.Buffer, response.ReceivedBytes, out returnVal))
+                        {
+                            await ReleaseLockkey(tcpClient).ConfigureAwait(false);
+                            continue;
+                        }
+
+                    }
+                    
+                    var targetValue = String.Format("rtp://{0}:{1}", localIp, localPort);
+                    var targetMsg = CreateSetMessage(i, "target", targetValue, _lockkey.Value);
+
+                    await tcpClient.SendAsync(targetMsg, targetMsg.Length, ipEndPoint, cancellationToken).ConfigureAwait(false);
+                    response = await tcpClient.ReceiveAsync(cancellationToken).ConfigureAwait(false);
+                    // parse response to make sure it worked
+                    if (!ParseReturnMessage(response.Buffer, response.ReceivedBytes, out returnVal))
+                    {
+                        await ReleaseLockkey(tcpClient).ConfigureAwait(false);
+                        continue;
+                    }
+
+                    break;
+                }
+            }
+        }
+
+        public async Task ChangeChannel(IHdHomerunChannelCommands commands, CancellationToken cancellationToken)
+        {
+            if (!_lockkey.HasValue)
+                return;
+
+            using (var tcpClient = _socketFactory.CreateTcpSocket(_remoteIp, HdHomeRunPort))
+            {
+                var commandList = commands.GetCommands();
+                foreach (Tuple<string, string> command in commandList)
+                {
+                    var channelMsg = CreateSetMessage(_activeTuner, command.Item1, command.Item2, _lockkey.Value);
+                    await tcpClient.SendAsync(channelMsg, channelMsg.Length, new IpEndPointInfo(_remoteIp, HdHomeRunPort), cancellationToken).ConfigureAwait(false);
+                    var response = await tcpClient.ReceiveAsync(cancellationToken).ConfigureAwait(false);
+                    // parse response to make sure it worked
+                    string returnVal;
+                    if (!ParseReturnMessage(response.Buffer, response.ReceivedBytes, out returnVal))
+                    {
+                        return;
+                    }
+                }
+            }
+        }
+
+        public async Task StopStreaming()
+        {
+            if (!_lockkey.HasValue)
+                return;
+
+            using (var socket = _socketFactory.CreateTcpSocket(_remoteIp, HdHomeRunPort))
+            {
+                await ReleaseLockkey(socket).ConfigureAwait(false);
+            }
+        }
+
+        private async Task ReleaseLockkey(ISocket tcpClient)
+        {
+            var releaseTarget = CreateSetMessage(_activeTuner, "target", "none", _lockkey);
+            await tcpClient.SendAsync(releaseTarget, releaseTarget.Length, new IpEndPointInfo(_remoteIp, HdHomeRunPort), CancellationToken.None).ConfigureAwait(false);
+            await tcpClient.ReceiveAsync(CancellationToken.None).ConfigureAwait(false);
+            var releaseKeyMsg = CreateSetMessage(_activeTuner, "lockkey", "none", _lockkey);
+            _lockkey = null;
+            await tcpClient.SendAsync(releaseKeyMsg, releaseKeyMsg.Length, new IpEndPointInfo(_remoteIp, HdHomeRunPort), CancellationToken.None).ConfigureAwait(false);
+            await tcpClient.ReceiveAsync(CancellationToken.None).ConfigureAwait(false);
+        }
+
+        private static byte[] CreateGetMessage(int tuner, string name)
+        {
+            var byteName = Encoding.UTF8.GetBytes(String.Format("/tuner{0}/{1}\0", tuner, name));
+            int messageLength = byteName.Length + 10; // 4 bytes for header + 4 bytes for crc + 2 bytes for tag name and length
+
+            var message = new byte[messageLength];
+
+            int offset = InsertHeaderAndName(byteName, messageLength, message);
+
+            bool flipEndian = BitConverter.IsLittleEndian;
+
+            // calculate crc and insert at the end of the message
+            var crcBytes = BitConverter.GetBytes(HdHomerunCrc.GetCrc32(message, messageLength - 4));
+            if (flipEndian)
+                Array.Reverse(crcBytes);
+            Buffer.BlockCopy(crcBytes, 0, message, offset, 4);
+
+            return message;
+        }
+
+        private static byte[] CreateSetMessage(int tuner, String name, String value, uint? lockkey)
+        {
+            var byteName = Encoding.UTF8.GetBytes(String.Format("/tuner{0}/{1}\0", tuner, name));
+            var byteValue = Encoding.UTF8.GetBytes(String.Format("{0}\0", value));
+
+            int messageLength = byteName.Length + byteValue.Length + 12;
+            if (lockkey.HasValue)
+                messageLength += 6;
+
+            var message = new byte[messageLength];
+
+            int offset = InsertHeaderAndName(byteName, messageLength, message);
+
+            bool flipEndian = BitConverter.IsLittleEndian;
+
+            message[offset] = GetSetValue;
+            offset++;
+            message[offset] = Convert.ToByte(byteValue.Length);
+            offset++;
+            Buffer.BlockCopy(byteValue, 0, message, offset, byteValue.Length);
+            offset += byteValue.Length;
+            if (lockkey.HasValue)
+            {
+                message[offset] = GetSetLockkey;
+                offset++;
+                message[offset] = (byte)4;
+                offset++;
+                var lockKeyBytes = BitConverter.GetBytes(lockkey.Value);
+                if (flipEndian)
+                    Array.Reverse(lockKeyBytes);
+                Buffer.BlockCopy(lockKeyBytes, 0, message, offset, 4);
+                offset += 4;
+            }
+
+            // calculate crc and insert at the end of the message
+            var crcBytes = BitConverter.GetBytes(HdHomerunCrc.GetCrc32(message, messageLength - 4));
+            if (flipEndian)
+                Array.Reverse(crcBytes);
+            Buffer.BlockCopy(crcBytes, 0, message, offset, 4);
+
+            return message;
+        }
+
+        private static int InsertHeaderAndName(byte[] byteName, int messageLength, byte[] message)
+        {
+            // check to see if we need to flip endiannes
+            bool flipEndian = BitConverter.IsLittleEndian;
+            int offset = 0;
+
+            // create header bytes
+            var getSetBytes = BitConverter.GetBytes(GetSetRequest);
+            var msgLenBytes = BitConverter.GetBytes((ushort)(messageLength - 8)); // Subtrace 4 bytes for header and 4 bytes for crc
+
+            if (flipEndian)
+            {
+                Array.Reverse(getSetBytes);
+                Array.Reverse(msgLenBytes);
+            }
+
+            // insert header bytes into message
+            Buffer.BlockCopy(getSetBytes, 0, message, offset, 2);
+            offset += 2;
+            Buffer.BlockCopy(msgLenBytes, 0, message, offset, 2);
+            offset += 2;
+
+            // insert tag name and length
+            message[offset] = GetSetName;
+            offset++;
+            message[offset] = Convert.ToByte(byteName.Length);
+            offset++;
+
+            // insert name string
+            Buffer.BlockCopy(byteName, 0, message, offset, byteName.Length);
+            offset += byteName.Length;
+
+            return offset;
+        }
+
+        private static bool ParseReturnMessage(byte[] buf, int numBytes, out string returnVal)
+        {
+            returnVal = String.Empty;
+
+            if (numBytes < 4)
+                return false;
+
+            var flipEndian = BitConverter.IsLittleEndian;
+            int offset = 0;
+            byte[] msgTypeBytes = new byte[2];
+            Buffer.BlockCopy(buf, offset, msgTypeBytes, 0, msgTypeBytes.Length);
+
+            if (flipEndian)
+                Array.Reverse(msgTypeBytes);
+
+            var msgType = BitConverter.ToUInt16(msgTypeBytes, 0);
+            offset += 2;
+
+            if (msgType != GetSetReply)
+                return false;
+
+            byte[] msgLengthBytes = new byte[2];
+            Buffer.BlockCopy(buf, offset, msgLengthBytes, 0, msgLengthBytes.Length);
+            if (flipEndian)
+                Array.Reverse(msgLengthBytes);
+
+            var msgLength = BitConverter.ToUInt16(msgLengthBytes, 0);
+            offset += 2;
+
+            if (numBytes < msgLength + 8)
+                return false;
+
+            var nameTag = buf[offset];
+            offset++;
+
+            var nameLength = buf[offset];
+            offset++;
+
+            // skip the name field to get to value for return
+            offset += nameLength;
+
+            var valueTag = buf[offset];
+            offset++;
+
+            var valueLength = buf[offset];
+            offset++;
+
+            returnVal = Encoding.UTF8.GetString(buf, offset, valueLength - 1); // remove null terminator
+            return true;
+        }
+
+        private class HdHomerunCrc
+        {
+            private static UInt32[] crc_table = {
+            0x00000000, 0x77073096, 0xee0e612c, 0x990951ba,
+            0x076dc419, 0x706af48f, 0xe963a535, 0x9e6495a3,
+            0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988,
+            0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91,
+            0x1db71064, 0x6ab020f2, 0xf3b97148, 0x84be41de,
+            0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7,
+            0x136c9856, 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec,
+            0x14015c4f, 0x63066cd9, 0xfa0f3d63, 0x8d080df5,
+            0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172,
+            0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b,
+            0x35b5a8fa, 0x42b2986c, 0xdbbbc9d6, 0xacbcf940,
+            0x32d86ce3, 0x45df5c75, 0xdcd60dcf, 0xabd13d59,
+            0x26d930ac, 0x51de003a, 0xc8d75180, 0xbfd06116,
+            0x21b4f4b5, 0x56b3c423, 0xcfba9599, 0xb8bda50f,
+            0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924,
+            0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d,
+            0x76dc4190, 0x01db7106, 0x98d220bc, 0xefd5102a,
+            0x71b18589, 0x06b6b51f, 0x9fbfe4a5, 0xe8b8d433,
+            0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818,
+            0x7f6a0dbb, 0x086d3d2d, 0x91646c97, 0xe6635c01,
+            0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e,
+            0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457,
+            0x65b0d9c6, 0x12b7e950, 0x8bbeb8ea, 0xfcb9887c,
+            0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65,
+            0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2,
+            0x4adfa541, 0x3dd895d7, 0xa4d1c46d, 0xd3d6f4fb,
+            0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0,
+            0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9,
+            0x5005713c, 0x270241aa, 0xbe0b1010, 0xc90c2086,
+            0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f,
+            0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4,
+            0x59b33d17, 0x2eb40d81, 0xb7bd5c3b, 0xc0ba6cad,
+            0xedb88320, 0x9abfb3b6, 0x03b6e20c, 0x74b1d29a,
+            0xead54739, 0x9dd277af, 0x04db2615, 0x73dc1683,
+            0xe3630b12, 0x94643b84, 0x0d6d6a3e, 0x7a6a5aa8,
+            0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1,
+            0xf00f9344, 0x8708a3d2, 0x1e01f268, 0x6906c2fe,
+            0xf762575d, 0x806567cb, 0x196c3671, 0x6e6b06e7,
+            0xfed41b76, 0x89d32be0, 0x10da7a5a, 0x67dd4acc,
+            0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5,
+            0xd6d6a3e8, 0xa1d1937e, 0x38d8c2c4, 0x4fdff252,
+            0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b,
+            0xd80d2bda, 0xaf0a1b4c, 0x36034af6, 0x41047a60,
+            0xdf60efc3, 0xa867df55, 0x316e8eef, 0x4669be79,
+            0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236,
+            0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f,
+            0xc5ba3bbe, 0xb2bd0b28, 0x2bb45a92, 0x5cb36a04,
+            0xc2d7ffa7, 0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d,
+            0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x026d930a,
+            0x9c0906a9, 0xeb0e363f, 0x72076785, 0x05005713,
+            0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38,
+            0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21,
+            0x86d3d2d4, 0xf1d4e242, 0x68ddb3f8, 0x1fda836e,
+            0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777,
+            0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c,
+            0x8f659eff, 0xf862ae69, 0x616bffd3, 0x166ccf45,
+            0xa00ae278, 0xd70dd2ee, 0x4e048354, 0x3903b3c2,
+            0xa7672661, 0xd06016f7, 0x4969474d, 0x3e6e77db,
+            0xaed16a4a, 0xd9d65adc, 0x40df0b66, 0x37d83bf0,
+            0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9,
+            0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6,
+            0xbad03605, 0xcdd70693, 0x54de5729, 0x23d967bf,
+            0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94,
+            0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d };
+
+            public static UInt32 GetCrc32(byte[] bytes, int numBytes)
+            {
+                var hash = 0xffffffff;
+                for (var i = 0; i < numBytes; i++)
+                    hash = (hash >> 8) ^ crc_table[(hash ^ bytes[i]) & 0xff];
+
+                var tmp = ~hash & 0xffffffff;
+                var b0 = tmp & 0xff;
+                var b1 = (tmp >> 8) & 0xff;
+                var b2 = (tmp >> 16) & 0xff;
+                var b3 = (tmp >> 24) & 0xff;
+                hash = (b0 << 24) | (b1 << 16) | (b2 << 8) | b3;
+                return hash;
+            }
+        }
+    }
+}

+ 294 - 0
Emby.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunUdpStream.cs

@@ -0,0 +1,294 @@
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Linq;
+using System.Text;
+using System.Threading;
+using System.Threading.Tasks;
+using MediaBrowser.Common.Net;
+using MediaBrowser.Controller;
+using MediaBrowser.Controller.Library;
+using MediaBrowser.Controller.LiveTv;
+using MediaBrowser.Model.Dto;
+using MediaBrowser.Model.IO;
+using MediaBrowser.Model.Logging;
+using MediaBrowser.Model.MediaInfo;
+using MediaBrowser.Model.Net;
+
+namespace Emby.Server.Implementations.LiveTv.TunerHosts.HdHomerun
+{
+    public class HdHomerunUdpStream : LiveStream, IDirectStreamProvider
+    {
+        private readonly ILogger _logger;
+        private readonly IHttpClient _httpClient;
+        private readonly IFileSystem _fileSystem;
+        private readonly IServerApplicationPaths _appPaths;
+        private readonly IServerApplicationHost _appHost;
+        private readonly ISocketFactory _socketFactory;
+
+        private readonly CancellationTokenSource _liveStreamCancellationTokenSource = new CancellationTokenSource();
+        private readonly TaskCompletionSource<bool> _liveStreamTaskCompletionSource = new TaskCompletionSource<bool>();
+        private readonly MulticastStream _multicastStream;
+        private readonly IHdHomerunChannelCommands _channelCommands;
+        private readonly int _numTuners;
+        private readonly INetworkManager _networkManager;
+
+        public HdHomerunUdpStream(MediaSourceInfo mediaSource, string originalStreamId, IHdHomerunChannelCommands channelCommands, int numTuners, IFileSystem fileSystem, IHttpClient httpClient, ILogger logger, IServerApplicationPaths appPaths, IServerApplicationHost appHost, ISocketFactory socketFactory, INetworkManager networkManager)
+            : base(mediaSource)
+        {
+            _fileSystem = fileSystem;
+            _httpClient = httpClient;
+            _logger = logger;
+            _appPaths = appPaths;
+            _appHost = appHost;
+            _socketFactory = socketFactory;
+            _networkManager = networkManager;
+            OriginalStreamId = originalStreamId;
+            _multicastStream = new MulticastStream(_logger);
+            _channelCommands = channelCommands;
+            _numTuners = numTuners;
+        }
+
+        protected override async Task OpenInternal(CancellationToken openCancellationToken)
+        {
+            _liveStreamCancellationTokenSource.Token.ThrowIfCancellationRequested();
+
+            var mediaSource = OriginalMediaSource;
+
+            var uri = new Uri(mediaSource.Path);
+            var localPort = _networkManager.GetRandomUnusedUdpPort();
+
+            _logger.Info("Opening HDHR UDP Live stream from {0}", uri.Host);
+
+            var taskCompletionSource = new TaskCompletionSource<bool>();
+
+            StartStreaming(uri.Host, localPort, taskCompletionSource, _liveStreamCancellationTokenSource.Token);
+
+            //OpenedMediaSource.Protocol = MediaProtocol.File;
+            //OpenedMediaSource.Path = tempFile;
+            //OpenedMediaSource.ReadAtNativeFramerate = true;
+
+            OpenedMediaSource.Path = _appHost.GetLocalApiUrl("127.0.0.1") + "/LiveTv/LiveStreamFiles/" + UniqueId + "/stream.ts";
+            OpenedMediaSource.Protocol = MediaProtocol.Http;
+            OpenedMediaSource.SupportsDirectPlay = false;
+            OpenedMediaSource.SupportsDirectStream = true;
+            OpenedMediaSource.SupportsTranscoding = true;
+
+            await taskCompletionSource.Task.ConfigureAwait(false);
+
+            //await Task.Delay(5000).ConfigureAwait(false);
+        }
+
+        public override Task Close()
+        {
+            _logger.Info("Closing HDHR UDP live stream");
+            _liveStreamCancellationTokenSource.Cancel();
+
+            return _liveStreamTaskCompletionSource.Task;
+        }
+
+        private async Task StartStreaming(string remoteIp, int localPort, TaskCompletionSource<bool> openTaskCompletionSource, CancellationToken cancellationToken)
+        {
+            await Task.Run(async () =>
+            {
+                var isFirstAttempt = true;
+                using (var udpClient = _socketFactory.CreateUdpSocket(localPort))
+                {
+                    using (var hdHomerunManager = new HdHomerunManager(_socketFactory))
+                    {
+                        var remoteAddress = _networkManager.ParseIpAddress(remoteIp);
+                        IpAddressInfo localAddress = null;
+                        using (var tcpSocket = _socketFactory.CreateSocket(remoteAddress.AddressFamily, SocketType.Stream, ProtocolType.Tcp, false))
+                        {
+                            try
+                            {
+                                tcpSocket.Connect(new IpEndPointInfo(remoteAddress, HdHomerunManager.HdHomeRunPort));
+                                localAddress = tcpSocket.LocalEndPoint.IpAddress;
+                                tcpSocket.Close();
+                            }
+                            catch (Exception)
+                            {
+                                _logger.Error("Unable to determine local ip address for Legacy HDHomerun stream.");
+                                return;
+                            }
+                        }
+
+                        while (!cancellationToken.IsCancellationRequested)
+                        {
+                            try
+                            {
+                                // send url to start streaming
+                                await hdHomerunManager.StartStreaming(remoteAddress, localAddress, localPort, _channelCommands, _numTuners, cancellationToken).ConfigureAwait(false);
+
+                                var response = await udpClient.ReceiveAsync(cancellationToken).ConfigureAwait(false);
+                                _logger.Info("Opened HDHR UDP stream from {0}", remoteAddress);
+
+                                if (!cancellationToken.IsCancellationRequested)
+                                {
+                                    Action onStarted = null;
+                                    if (isFirstAttempt)
+                                    {
+                                        onStarted = () => openTaskCompletionSource.TrySetResult(true);
+                                    }
+
+                                    var stream = new UdpClientStream(udpClient);
+                                    await _multicastStream.CopyUntilCancelled(stream, onStarted, cancellationToken).ConfigureAwait(false);
+                                }
+                            }
+                            catch (OperationCanceledException)
+                            {
+                                break;
+                            }
+                            catch (Exception ex)
+                            {
+                                if (isFirstAttempt)
+                                {
+                                    _logger.ErrorException("Error opening live stream:", ex);
+                                    openTaskCompletionSource.TrySetException(ex);
+                                    break;
+                                }
+
+                                _logger.ErrorException("Error copying live stream, will reopen", ex);
+                            }
+
+                            isFirstAttempt = false;
+                        }
+
+                        await hdHomerunManager.StopStreaming().ConfigureAwait(false);
+                        udpClient.Dispose();
+                        _liveStreamTaskCompletionSource.TrySetResult(true);
+                    }
+                }
+
+            }).ConfigureAwait(false);
+        }
+
+        public Task CopyToAsync(Stream stream, CancellationToken cancellationToken)
+        {
+            return _multicastStream.CopyToAsync(stream);
+        }
+    }
+
+    // This handles the ReadAsync function only of a Stream object
+    // This is used to wrap a UDP socket into a stream for MulticastStream which only uses ReadAsync
+    public class UdpClientStream : Stream
+    {
+        private static int RtpHeaderBytes = 12;
+        private static int PacketSize = 1316;
+        private readonly ISocket _udpClient;
+        bool disposed;
+
+        public UdpClientStream(ISocket udpClient) : base()
+        {
+            _udpClient = udpClient;
+        }
+
+        public override async Task<int> ReadAsync(byte[] buffer, int offset, int count, CancellationToken cancellationToken)
+        {
+            if (buffer == null)
+                throw new ArgumentNullException("buffer");
+
+            if (offset + count < 0)
+                throw new ArgumentOutOfRangeException("offset + count must not be negative", "offset+count");
+
+            if (offset + count > buffer.Length)
+                throw new ArgumentException("offset + count must not be greater than the length of buffer", "offset+count");
+
+            if (disposed)
+                throw new ObjectDisposedException(typeof(UdpClientStream).ToString());
+
+            // This will always receive a 1328 packet size (PacketSize + RtpHeaderSize)
+            // The RTP header will be stripped so see how many reads we need to make to fill the buffer.
+            int numReads = count / PacketSize;
+            int totalBytesRead = 0;
+
+            for (int i = 0; i < numReads; ++i)
+            {
+                var data = await _udpClient.ReceiveAsync(cancellationToken).ConfigureAwait(false);
+
+                var bytesRead = data.ReceivedBytes - RtpHeaderBytes;
+
+                // remove rtp header
+                Buffer.BlockCopy(data.Buffer, RtpHeaderBytes, buffer, offset, bytesRead);
+                offset += bytesRead;
+                totalBytesRead += bytesRead;
+            }
+            return totalBytesRead;
+        }
+
+        protected override void Dispose(bool disposing)
+        {
+            disposed = true;
+        }
+
+        public override bool CanRead
+        {
+            get
+            {
+                throw new NotImplementedException();
+            }
+        }
+
+        public override bool CanSeek
+        {
+            get
+            {
+                throw new NotImplementedException();
+            }
+        }
+
+        public override bool CanWrite
+        {
+            get
+            {
+                throw new NotImplementedException();
+            }
+        }
+
+        public override long Length
+        {
+            get
+            {
+                throw new NotImplementedException();
+            }
+        }
+
+        public override long Position
+        {
+            get
+            {
+                throw new NotImplementedException();
+            }
+
+            set
+            {
+                throw new NotImplementedException();
+            }
+        }
+
+        public override void Flush()
+        {
+            throw new NotImplementedException();
+        }
+
+        public override int Read(byte[] buffer, int offset, int count)
+        {
+            throw new NotImplementedException();
+        }
+
+        public override long Seek(long offset, SeekOrigin origin)
+        {
+            throw new NotImplementedException();
+        }
+
+        public override void SetLength(long value)
+        {
+            throw new NotImplementedException();
+        }
+
+        public override void Write(byte[] buffer, int offset, int count)
+        {
+            throw new NotImplementedException();
+        }
+    }
+}

+ 0 - 1
Emby.Server.Implementations/LiveTv/TunerHosts/M3UTunerHost.cs

@@ -162,7 +162,6 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts
 
                     Id = channel.Path.GetMD5().ToString("N"),
                     IsInfiniteStream = true,
-                    SupportsDirectStream = false,
                     IsRemote = true
                 };
 

+ 0 - 19
Emby.Server.Implementations/LiveTv/TunerHosts/MulticastStream.cs

@@ -16,7 +16,6 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts
         private const int BufferSize = 81920;
         private CancellationToken _cancellationToken;
         private readonly ILogger _logger;
-        private readonly ConcurrentQueue<byte[]> _sharedBuffer = new ConcurrentQueue<byte[]>();
 
         public MulticastStream(ILogger logger)
         {
@@ -38,14 +37,6 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts
                     byte[] copy = new byte[bytesRead];
                     Buffer.BlockCopy(buffer, 0, copy, 0, bytesRead);
 
-                    _sharedBuffer.Enqueue(copy);
-
-                    while (_sharedBuffer.Count > 3000)
-                    {
-                        byte[] bytes;
-                        _sharedBuffer.TryDequeue(out bytes);
-                    }
-
                     var allStreams = _outputStreams.ToList();
                     foreach (var stream in allStreams)
                     {
@@ -74,16 +65,6 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts
                 OnFinished = OnFinished
             };
 
-            var list = new List<byte>();
-            foreach (var bytes in _sharedBuffer)
-            {
-                list.AddRange(bytes);
-            }
-
-            _logger.Info("QueueStream started with {0} initial bytes", list.Count);
-
-            result.Queue(list.ToArray());
-
             _outputStreams.TryAdd(result.Id, result);
 
             result.Start(_cancellationToken);

+ 0 - 39
Emby.Server.Implementations/Sorting/BudgetComparer.cs

@@ -1,39 +0,0 @@
-using MediaBrowser.Controller.Entities;
-using MediaBrowser.Controller.Sorting;
-using MediaBrowser.Model.Querying;
-
-namespace Emby.Server.Implementations.Sorting
-{
-    public class BudgetComparer : IBaseItemComparer
-    {
-        /// <summary>
-        /// Compares the specified x.
-        /// </summary>
-        /// <param name="x">The x.</param>
-        /// <param name="y">The y.</param>
-        /// <returns>System.Int32.</returns>
-        public int Compare(BaseItem x, BaseItem y)
-        {
-            return GetValue(x).CompareTo(GetValue(y));
-        }
-
-        private double GetValue(BaseItem x)
-        {
-            var hasBudget = x as IHasBudget;
-            if (hasBudget != null)
-            {
-                return hasBudget.Budget ?? 0;
-            }
-            return 0;
-        }
-
-        /// <summary>
-        /// Gets the name.
-        /// </summary>
-        /// <value>The name.</value>
-        public string Name
-        {
-            get { return ItemSortBy.Budget; }
-        }
-    }
-}

+ 0 - 39
Emby.Server.Implementations/Sorting/RevenueComparer.cs

@@ -1,39 +0,0 @@
-using MediaBrowser.Controller.Entities;
-using MediaBrowser.Controller.Sorting;
-using MediaBrowser.Model.Querying;
-
-namespace Emby.Server.Implementations.Sorting
-{
-    public class RevenueComparer : IBaseItemComparer
-    {
-        /// <summary>
-        /// Compares the specified x.
-        /// </summary>
-        /// <param name="x">The x.</param>
-        /// <param name="y">The y.</param>
-        /// <returns>System.Int32.</returns>
-        public int Compare(BaseItem x, BaseItem y)
-        {
-            return GetValue(x).CompareTo(GetValue(y));
-        }
-
-        private double GetValue(BaseItem x)
-        {
-            var hasBudget = x as IHasBudget;
-            if (hasBudget != null)
-            {
-                return hasBudget.Revenue ?? 0;
-            }
-            return 0;
-        }
-
-        /// <summary>
-        /// Gets the name.
-        /// </summary>
-        /// <value>The name.</value>
-        public string Name
-        {
-            get { return ItemSortBy.Revenue; }
-        }
-    }
-}

+ 2 - 2
Emby.Server.Implementations/Udp/UdpServer.cs

@@ -128,7 +128,7 @@ namespace Emby.Server.Implementations.Udp
         /// <summary>
         /// The _udp client
         /// </summary>
-        private IUdpSocket _udpClient;
+        private ISocket _udpClient;
         private readonly ISocketFactory _socketFactory;
 
         /// <summary>
@@ -148,7 +148,7 @@ namespace Emby.Server.Implementations.Udp
             {
                 try
                 {
-                    var result = await _udpClient.ReceiveAsync().ConfigureAwait(false);
+                    var result = await _udpClient.ReceiveAsync(CancellationToken.None).ConfigureAwait(false);
 
                     OnMessageReceived(result);
                 }

+ 9 - 9
Emby.Server.Implementations/Updates/InstallationManager.cs

@@ -162,15 +162,15 @@ namespace Emby.Server.Implementations.Updates
             string packageType = null,
             Version applicationVersion = null)
         {
-            var data = new Dictionary<string, string>
-            {
-                { "key", _securityManager.SupporterKey },
-                { "mac", _applicationHost.SystemId },
-                { "systemid", _applicationHost.SystemId }
-            };
-
             if (withRegistration)
             {
+                var data = new Dictionary<string, string>
+                {
+                    { "key", _securityManager.SupporterKey },
+                    { "mac", _applicationHost.SystemId },
+                    { "systemid", _applicationHost.SystemId }
+                };
+
                 using (var json = await _httpClient.Post("https://www.mb3admin.com/admin/service/package/retrieveall", data, cancellationToken).ConfigureAwait(false))
                 {
                     cancellationToken.ThrowIfCancellationRequested();
@@ -353,7 +353,7 @@ namespace Emby.Server.Implementations.Updates
         /// <returns>Task{PackageVersionInfo}.</returns>
         public async Task<PackageVersionInfo> GetPackage(string name, string guid, PackageVersionClass classification, Version version)
         {
-            var packages = await GetAvailablePackages(CancellationToken.None).ConfigureAwait(false);
+            var packages = await GetAvailablePackages(CancellationToken.None, false).ConfigureAwait(false);
 
             var package = packages.FirstOrDefault(p => string.Equals(p.guid, guid ?? "none", StringComparison.OrdinalIgnoreCase))
                             ?? packages.FirstOrDefault(p => p.name.Equals(name, StringComparison.OrdinalIgnoreCase));
@@ -376,7 +376,7 @@ namespace Emby.Server.Implementations.Updates
         /// <returns>Task{PackageVersionInfo}.</returns>
         public async Task<PackageVersionInfo> GetLatestCompatibleVersion(string name, string guid, Version currentServerVersion, PackageVersionClass classification = PackageVersionClass.Release)
         {
-            var packages = await GetAvailablePackages(CancellationToken.None).ConfigureAwait(false);
+            var packages = await GetAvailablePackages(CancellationToken.None, false).ConfigureAwait(false);
 
             return GetLatestCompatibleVersion(packages, name, guid, currentServerVersion, classification);
         }

+ 0 - 4
MediaBrowser.Api/MediaBrowser.Api.csproj

@@ -134,10 +134,6 @@
     <Compile Include="SearchService.cs" />
     <Compile Include="Session\SessionsService.cs" />
     <Compile Include="SimilarItemsHelper.cs" />
-    <Compile Include="Sync\SyncHelper.cs" />
-    <Compile Include="Sync\SyncJobWebSocketListener.cs" />
-    <Compile Include="Sync\SyncJobsWebSocketListener.cs" />
-    <Compile Include="Sync\SyncService.cs" />
     <Compile Include="System\ActivityLogService.cs" />
     <Compile Include="System\ActivityLogWebSocketListener.cs" />
     <Compile Include="System\SystemService.cs" />

+ 1 - 0
MediaBrowser.Api/Playback/Progressive/AudioService.cs

@@ -31,6 +31,7 @@ namespace MediaBrowser.Api.Playback.Progressive
     /// <summary>
     /// Class AudioService
     /// </summary>
+    [Authenticated]
     public class AudioService : BaseProgressiveStreamingService
     {
         /// <summary>

+ 0 - 85
MediaBrowser.Api/Sync/SyncHelper.cs

@@ -1,85 +0,0 @@
-using MediaBrowser.Model.Dto;
-using MediaBrowser.Model.Sync;
-using System.Collections.Generic;
-
-namespace MediaBrowser.Api.Sync
-{
-    public static class SyncHelper
-    {
-        public static List<SyncJobOption> GetSyncOptions(List<BaseItemDto> items)
-        {
-            List<SyncJobOption> options = new List<SyncJobOption>();
-
-            foreach (BaseItemDto item in items)
-            {
-                if (item.SupportsSync ?? false)
-                {
-                    if (item.IsVideo)
-                    {
-                        options.Add(SyncJobOption.Quality);
-                        options.Add(SyncJobOption.Profile);
-                        if (items.Count > 1)
-                        {
-                            options.Add(SyncJobOption.UnwatchedOnly);
-                        }
-                        break;
-                    }
-                    if (item.IsAudio)
-                    {
-                        options.Add(SyncJobOption.Quality);
-                        options.Add(SyncJobOption.Profile);
-                        break;
-                    }
-                    if (item.IsMusicGenre || item.IsArtist|| item.IsType("musicalbum"))
-                    {
-                        options.Add(SyncJobOption.Quality);
-                        options.Add(SyncJobOption.Profile);
-                        options.Add(SyncJobOption.ItemLimit);
-                        break;
-                    }
-                    if ((item.IsFolder ?? false) && !item.IsMusicGenre && !item.IsArtist && !item.IsType("musicalbum") && !item.IsGameGenre)
-                    {
-                        options.Add(SyncJobOption.Quality);
-                        options.Add(SyncJobOption.Profile);
-                        options.Add(SyncJobOption.UnwatchedOnly);
-                        break;
-                    }
-                    if (item.IsGenre)
-                    {
-                        options.Add(SyncJobOption.SyncNewContent);
-                        options.Add(SyncJobOption.ItemLimit);
-                        break;
-                    }
-                }
-            }
-
-            foreach (BaseItemDto item in items)
-            {
-                if (item.SupportsSync ?? false)
-                {
-                    if ((item.IsFolder ?? false) || item.IsGameGenre || item.IsMusicGenre || item.IsGenre || item.IsArtist || item.IsStudio || item.IsPerson)
-                    {
-                        options.Add(SyncJobOption.SyncNewContent);
-                        options.Add(SyncJobOption.ItemLimit);
-                        break;
-                    }
-                }
-            }
-
-            return options;
-        }
-
-        public static List<SyncJobOption> GetSyncOptions(SyncCategory category)
-        {
-            List<SyncJobOption> options = new List<SyncJobOption>();
-
-            options.Add(SyncJobOption.Quality);
-            options.Add(SyncJobOption.Profile);
-            options.Add(SyncJobOption.UnwatchedOnly);
-            options.Add(SyncJobOption.SyncNewContent);
-            options.Add(SyncJobOption.ItemLimit);
-
-            return options;
-        }
-    }
-}

+ 0 - 120
MediaBrowser.Api/Sync/SyncJobWebSocketListener.cs

@@ -1,120 +0,0 @@
-using MediaBrowser.Controller.Sync;
-using MediaBrowser.Model.Events;
-using MediaBrowser.Model.Logging;
-using MediaBrowser.Model.Sync;
-using System;
-using System.Linq;
-using System.Threading.Tasks;
-using MediaBrowser.Model.Threading;
-
-namespace MediaBrowser.Api.Sync
-{
-    /// <summary>
-    /// Class SessionInfoWebSocketListener
-    /// </summary>
-    class SyncJobWebSocketListener : BasePeriodicWebSocketListener<CompleteSyncJobInfo, WebSocketListenerState>
-    {
-        /// <summary>
-        /// Gets the name.
-        /// </summary>
-        /// <value>The name.</value>
-        protected override string Name
-        {
-            get { return "SyncJob"; }
-        }
-
-        private readonly ISyncManager _syncManager;
-        private string _jobId;
-
-        public SyncJobWebSocketListener(ILogger logger, ISyncManager syncManager, ITimerFactory timerFactory)
-            : base(logger, timerFactory)
-        {
-            _syncManager = syncManager;
-            _syncManager.SyncJobCancelled += _syncManager_SyncJobCancelled;
-            _syncManager.SyncJobUpdated += _syncManager_SyncJobUpdated;
-            _syncManager.SyncJobItemCreated += _syncManager_SyncJobItemCreated;
-            _syncManager.SyncJobItemUpdated += _syncManager_SyncJobItemUpdated;
-        }
-
-        void _syncManager_SyncJobItemUpdated(object sender, GenericEventArgs<SyncJobItem> e)
-        {
-            if (string.Equals(e.Argument.Id, _jobId, StringComparison.Ordinal))
-            {
-                SendData(false);
-            }
-        }
-
-        void _syncManager_SyncJobItemCreated(object sender, GenericEventArgs<SyncJobItem> e)
-        {
-            if (string.Equals(e.Argument.Id, _jobId, StringComparison.Ordinal))
-            {
-                SendData(true);
-            }
-        }
-
-        protected override void ParseMessageParams(string[] values)
-        {
-            base.ParseMessageParams(values);
-
-            if (values.Length > 0)
-            {
-                _jobId = values[0];
-            }
-        }
-
-        void _syncManager_SyncJobUpdated(object sender, GenericEventArgs<SyncJob> e)
-        {
-            if (string.Equals(e.Argument.Id, _jobId, StringComparison.Ordinal))
-            {
-                SendData(false);
-            }
-        }
-
-        void _syncManager_SyncJobCancelled(object sender, GenericEventArgs<SyncJob> e)
-        {
-            if (string.Equals(e.Argument.Id, _jobId, StringComparison.Ordinal))
-            {
-                SendData(true);
-            }
-        }
-
-        /// <summary>
-        /// Gets the data to send.
-        /// </summary>
-        /// <param name="state">The state.</param>
-        /// <returns>Task{SystemInfo}.</returns>
-        protected override Task<CompleteSyncJobInfo> GetDataToSend(WebSocketListenerState state)
-        {
-            var job = _syncManager.GetJob(_jobId);
-            var items = _syncManager.GetJobItems(new SyncJobItemQuery
-            {
-                AddMetadata = true,
-                JobId = _jobId
-            });
-
-            var info = new CompleteSyncJobInfo
-            {
-                Job = job,
-                JobItems = items.Items.ToList()
-            };
-
-            return Task.FromResult(info);
-        }
-
-        protected override bool SendOnTimer
-        {
-            get
-            {
-                return false;
-            }
-        }
-
-        protected override void Dispose(bool dispose)
-        {
-            _syncManager.SyncJobCancelled -= _syncManager_SyncJobCancelled;
-            _syncManager.SyncJobUpdated -= _syncManager_SyncJobUpdated;
-
-            base.Dispose(dispose);
-        }
-    }
-}

+ 0 - 101
MediaBrowser.Api/Sync/SyncJobsWebSocketListener.cs

@@ -1,101 +0,0 @@
-using MediaBrowser.Controller.Sync;
-using MediaBrowser.Model.Logging;
-using MediaBrowser.Model.Sync;
-using System.Collections.Generic;
-using System.Threading.Tasks;
-using MediaBrowser.Model.Threading;
-
-namespace MediaBrowser.Api.Sync
-{
-    /// <summary>
-    /// Class SessionInfoWebSocketListener
-    /// </summary>
-    class SyncJobsWebSocketListener : BasePeriodicWebSocketListener<IEnumerable<SyncJob>, WebSocketListenerState>
-    {
-        /// <summary>
-        /// Gets the name.
-        /// </summary>
-        /// <value>The name.</value>
-        protected override string Name
-        {
-            get { return "SyncJobs"; }
-        }
-
-        private readonly ISyncManager _syncManager;
-        private string _userId;
-        private string _targetId;
-
-        public SyncJobsWebSocketListener(ILogger logger, ISyncManager syncManager, ITimerFactory timerFactory)
-            : base(logger, timerFactory)
-        {
-            _syncManager = syncManager;
-            _syncManager.SyncJobCancelled += _syncManager_SyncJobCancelled;
-            _syncManager.SyncJobCreated += _syncManager_SyncJobCreated;
-            _syncManager.SyncJobUpdated += _syncManager_SyncJobUpdated;
-        }
-
-        protected override void ParseMessageParams(string[] values)
-        {
-            base.ParseMessageParams(values);
-
-            if (values.Length > 0)
-            {
-                _userId = values[0];
-            }
-
-            if (values.Length > 1)
-            {
-                _targetId = values[1];
-            }
-        }
-
-        void _syncManager_SyncJobUpdated(object sender, Model.Events.GenericEventArgs<SyncJob> e)
-        {
-            SendData(false);
-        }
-
-        void _syncManager_SyncJobCreated(object sender, Model.Events.GenericEventArgs<SyncJobCreationResult> e)
-        {
-            SendData(true);
-        }
-
-        void _syncManager_SyncJobCancelled(object sender, Model.Events.GenericEventArgs<SyncJob> e)
-        {
-            SendData(true);
-        }
-
-        /// <summary>
-        /// Gets the data to send.
-        /// </summary>
-        /// <param name="state">The state.</param>
-        /// <returns>Task{SystemInfo}.</returns>
-        protected override async Task<IEnumerable<SyncJob>> GetDataToSend(WebSocketListenerState state)
-        {
-            var jobs = await _syncManager.GetJobs(new SyncJobQuery
-            {
-                UserId = _userId,
-                TargetId = _targetId
-
-            }).ConfigureAwait(false);
-
-            return jobs.Items;
-        }
-
-        protected override bool SendOnTimer
-        {
-            get
-            {
-                return false;
-            }
-        }
-
-        protected override void Dispose(bool dispose)
-        {
-            _syncManager.SyncJobCancelled -= _syncManager_SyncJobCancelled;
-            _syncManager.SyncJobCreated -= _syncManager_SyncJobCreated;
-            _syncManager.SyncJobUpdated -= _syncManager_SyncJobUpdated;
-
-            base.Dispose(dispose);
-        }
-    }
-}

+ 0 - 396
MediaBrowser.Api/Sync/SyncService.cs

@@ -1,396 +0,0 @@
-using MediaBrowser.Common.Extensions;
-using MediaBrowser.Controller.Dto;
-using MediaBrowser.Controller.Library;
-using MediaBrowser.Controller.Net;
-using MediaBrowser.Controller.Sync;
-using MediaBrowser.Model.Querying;
-using MediaBrowser.Model.Sync;
-using MediaBrowser.Model.Users;
-using System;
-using System.Collections.Generic;
-using System.Linq;
-using System.Threading.Tasks;
-using MediaBrowser.Model.Services;
-
-namespace MediaBrowser.Api.Sync
-{
-    [Route("/Sync/Jobs/{Id}", "DELETE", Summary = "Cancels a sync job.")]
-    public class CancelSyncJob : IReturnVoid
-    {
-        [ApiMember(Name = "Id", Description = "Id", IsRequired = true, DataType = "string", ParameterType = "path", Verb = "GET")]
-        public string Id { get; set; }
-    }
-
-    [Route("/Sync/Jobs/{Id}", "GET", Summary = "Gets a sync job.")]
-    public class GetSyncJob : IReturn<SyncJob>
-    {
-        [ApiMember(Name = "Id", Description = "Id", IsRequired = true, DataType = "string", ParameterType = "path", Verb = "GET")]
-        public string Id { get; set; }
-    }
-
-    [Route("/Sync/Jobs/{Id}", "POST", Summary = "Updates a sync job.")]
-    public class UpdateSyncJob : SyncJob, IReturnVoid
-    {
-    }
-
-    [Route("/Sync/JobItems", "GET", Summary = "Gets sync job items.")]
-    public class GetSyncJobItems : SyncJobItemQuery, IReturn<QueryResult<SyncJobItem>>
-    {
-    }
-
-    [Route("/Sync/JobItems/{Id}/Enable", "POST", Summary = "Enables a cancelled or queued sync job item")]
-    public class EnableSyncJobItem : IReturnVoid
-    {
-        [ApiMember(Name = "Id", Description = "Id", IsRequired = true, DataType = "string", ParameterType = "path", Verb = "POST")]
-        public string Id { get; set; }
-    }
-
-    [Route("/Sync/JobItems/{Id}/MarkForRemoval", "POST", Summary = "Marks a job item for removal")]
-    public class MarkJobItemForRemoval : IReturnVoid
-    {
-        [ApiMember(Name = "Id", Description = "Id", IsRequired = true, DataType = "string", ParameterType = "path", Verb = "POST")]
-        public string Id { get; set; }
-    }
-
-    [Route("/Sync/JobItems/{Id}/UnmarkForRemoval", "POST", Summary = "Unmarks a job item for removal")]
-    public class UnmarkJobItemForRemoval : IReturnVoid
-    {
-        [ApiMember(Name = "Id", Description = "Id", IsRequired = true, DataType = "string", ParameterType = "path", Verb = "POST")]
-        public string Id { get; set; }
-    }
-
-    [Route("/Sync/JobItems/{Id}", "DELETE", Summary = "Cancels a sync job item")]
-    public class CancelSyncJobItem : IReturnVoid
-    {
-        [ApiMember(Name = "Id", Description = "Id", IsRequired = true, DataType = "string", ParameterType = "path", Verb = "DELETE")]
-        public string Id { get; set; }
-    }
-
-    [Route("/Sync/Items/Cancel", "POST", Summary = "Cancels items from a sync target")]
-    [Route("/Sync/{TargetId}/Items", "DELETE", Summary = "Cancels items from a sync target")]
-    public class CancelItems : IReturnVoid
-    {
-        [ApiMember(Name = "TargetId", Description = "TargetId", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "Items")]
-        public string TargetId { get; set; }
-
-        [ApiMember(Name = "ItemIds", Description = "ItemIds", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "Items")]
-        public string ItemIds { get; set; }
-    }
-
-    [Route("/Sync/Jobs", "GET", Summary = "Gets sync jobs.")]
-    public class GetSyncJobs : SyncJobQuery, IReturn<QueryResult<SyncJob>>
-    {
-    }
-
-    [Route("/Sync/Jobs", "POST", Summary = "Gets sync jobs.")]
-    public class CreateSyncJob : SyncJobRequest, IReturn<SyncJobCreationResult>
-    {
-    }
-
-    [Route("/Sync/Targets", "GET", Summary = "Gets a list of available sync targets.")]
-    public class GetSyncTargets : IReturn<List<SyncTarget>>
-    {
-        [ApiMember(Name = "UserId", Description = "UserId", IsRequired = true, DataType = "string", ParameterType = "query", Verb = "GET")]
-        public string UserId { get; set; }
-    }
-
-    [Route("/Sync/Options", "GET", Summary = "Gets a list of available sync targets.")]
-    public class GetSyncDialogOptions : IReturn<SyncDialogOptions>
-    {
-        [ApiMember(Name = "UserId", Description = "UserId", IsRequired = true, DataType = "string", ParameterType = "query", Verb = "GET")]
-        public string UserId { get; set; }
-
-        [ApiMember(Name = "ItemIds", Description = "ItemIds", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET")]
-        public string ItemIds { get; set; }
-
-        [ApiMember(Name = "ParentId", Description = "ParentId", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET")]
-        public string ParentId { get; set; }
-
-        [ApiMember(Name = "TargetId", Description = "TargetId", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET")]
-        public string TargetId { get; set; }
-
-        [ApiMember(Name = "Category", Description = "Category", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET")]
-        public SyncCategory? Category { get; set; }
-    }
-
-    [Route("/Sync/JobItems/{Id}/Transferred", "POST", Summary = "Reports that a sync job item has successfully been transferred.")]
-    public class ReportSyncJobItemTransferred : IReturnVoid
-    {
-        [ApiMember(Name = "Id", Description = "Id", IsRequired = true, DataType = "string", ParameterType = "path", Verb = "POST")]
-        public string Id { get; set; }
-    }
-
-    [Route("/Sync/JobItems/{Id}/File", "GET", Summary = "Gets a sync job item file")]
-    public class GetSyncJobItemFile
-    {
-        [ApiMember(Name = "Id", Description = "Id", IsRequired = true, DataType = "string", ParameterType = "path", Verb = "GET")]
-        public string Id { get; set; }
-    }
-
-    [Route("/Sync/JobItems/{Id}/AdditionalFiles", "GET", Summary = "Gets a sync job item file")]
-    public class GetSyncJobItemAdditionalFile
-    {
-        [ApiMember(Name = "Id", Description = "Id", IsRequired = true, DataType = "string", ParameterType = "path", Verb = "GET")]
-        public string Id { get; set; }
-
-        [ApiMember(Name = "Name", Description = "Name", IsRequired = true, DataType = "string", ParameterType = "query", Verb = "GET")]
-        public string Name { get; set; }
-    }
-
-    [Route("/Sync/OfflineActions", "POST", Summary = "Reports an action that occurred while offline.")]
-    public class ReportOfflineActions : List<UserAction>, IReturnVoid
-    {
-    }
-
-    [Route("/Sync/Items/Ready", "GET", Summary = "Gets ready to download sync items.")]
-    public class GetReadySyncItems : IReturn<List<SyncedItem>>
-    {
-        [ApiMember(Name = "TargetId", Description = "TargetId", IsRequired = true, DataType = "string", ParameterType = "query", Verb = "GET")]
-        public string TargetId { get; set; }
-    }
-
-    [Route("/Sync/Data", "POST", Summary = "Syncs data between device and server")]
-    public class SyncData : SyncDataRequest, IReturn<SyncDataResponse>
-    {
-    }
-
-    [Authenticated]
-    public class SyncService : BaseApiService
-    {
-        private readonly ISyncManager _syncManager;
-        private readonly IDtoService _dtoService;
-        private readonly ILibraryManager _libraryManager;
-        private readonly IUserManager _userManager;
-        private readonly IAuthorizationContext _authContext;
-
-        public SyncService(ISyncManager syncManager, IDtoService dtoService, ILibraryManager libraryManager, IUserManager userManager, IAuthorizationContext authContext)
-        {
-            _syncManager = syncManager;
-            _dtoService = dtoService;
-            _libraryManager = libraryManager;
-            _userManager = userManager;
-            _authContext = authContext;
-        }
-
-        public object Get(GetSyncTargets request)
-        {
-            var result = _syncManager.GetSyncTargets(request.UserId);
-
-            return ToOptimizedResult(result);
-        }
-
-        public async Task<object> Get(GetSyncJobs request)
-        {
-            var result = await _syncManager.GetJobs(request).ConfigureAwait(false);
-
-            return ToOptimizedResult(result);
-        }
-
-        public object Get(GetSyncJobItems request)
-        {
-            var result = _syncManager.GetJobItems(request);
-
-            return ToOptimizedResult(result);
-        }
-
-        public object Get(GetSyncJob request)
-        {
-            var result = _syncManager.GetJob(request.Id);
-
-            return ToOptimizedResult(result);
-        }
-
-        public void Delete(CancelSyncJob request)
-        {
-            var task = _syncManager.CancelJob(request.Id);
-
-            Task.WaitAll(task);
-        }
-
-        public async Task<object> Post(CreateSyncJob request)
-        {
-            var result = await _syncManager.CreateJob(request).ConfigureAwait(false);
-
-            return ToOptimizedResult(result);
-        }
-
-        public void Any(CancelItems request)
-        {
-            var itemIds = request.ItemIds.Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries);
-
-            var task = _syncManager.CancelItems(request.TargetId, itemIds);
-
-            Task.WaitAll(task);
-        }
-
-        public void Post(ReportSyncJobItemTransferred request)
-        {
-            var task = _syncManager.ReportSyncJobItemTransferred(request.Id);
-
-            Task.WaitAll(task);
-        }
-
-        public async Task<object> Get(GetSyncJobItemFile request)
-        {
-            var jobItem = _syncManager.GetJobItem(request.Id);
-
-            if (jobItem == null)
-            {
-                throw new ResourceNotFoundException();
-            }
-
-            if (jobItem.Status < SyncJobItemStatus.ReadyToTransfer)
-            {
-                throw new ArgumentException("The job item is not yet ready for transfer.");
-            }
-
-            await _syncManager.ReportSyncJobItemTransferBeginning(request.Id).ConfigureAwait(false);
-
-            return await ResultFactory.GetStaticFileResult(Request, new StaticFileResultOptions
-            {
-                Path = jobItem.OutputPath,
-                OnError = () =>
-                {
-                    var failedTask = _syncManager.ReportSyncJobItemTransferFailed(request.Id);
-                    Task.WaitAll(failedTask);
-                }
-
-            }).ConfigureAwait(false);
-        }
-
-        public async Task<object> Get(GetSyncDialogOptions request)
-        {
-            var result = new SyncDialogOptions();
-
-            result.Targets = _syncManager.GetSyncTargets(request.UserId)
-                .ToList();
-
-            var auth = _authContext.GetAuthorizationInfo(Request);
-            var authenticatedUser = _userManager.GetUserById(auth.UserId);
-
-            if (!string.IsNullOrWhiteSpace(request.TargetId))
-            {
-                result.Targets = result.Targets
-                    .Where(i => string.Equals(i.Id, request.TargetId, StringComparison.OrdinalIgnoreCase))
-                    .ToList();
-
-                result.QualityOptions = _syncManager
-                    .GetQualityOptions(request.TargetId, authenticatedUser)
-                    .ToList();
-
-                result.ProfileOptions = _syncManager
-                    .GetProfileOptions(request.TargetId, authenticatedUser)
-                    .ToList();
-            }
-
-            if (request.Category.HasValue)
-            {
-                result.Options = SyncHelper.GetSyncOptions(request.Category.Value);
-            }
-            else
-            {
-                var dtoOptions = new DtoOptions
-                {
-                    Fields = new List<ItemFields>
-                    {
-                        ItemFields.SyncInfo,
-                        ItemFields.BasicSyncInfo
-                    }
-                };
-
-                var items = request.ItemIds.Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries)
-                    .Select(_libraryManager.GetItemById)
-                    .Where(i => i != null);
-
-                var dtos = (await _dtoService.GetBaseItemDtos(items, dtoOptions, authenticatedUser).ConfigureAwait(false));
-
-                result.Options = SyncHelper.GetSyncOptions(dtos);
-            }
-
-            return ToOptimizedResult(result);
-        }
-
-        public void Post(ReportOfflineActions request)
-        {
-            var task = PostAsync(request);
-
-            Task.WaitAll(task);
-        }
-
-        public async Task PostAsync(ReportOfflineActions request)
-        {
-            foreach (var action in request)
-            {
-                await _syncManager.ReportOfflineAction(action).ConfigureAwait(false);
-            }
-        }
-
-        public async Task<object> Get(GetReadySyncItems request)
-        {
-            var result = await _syncManager.GetReadySyncItems(request.TargetId).ConfigureAwait(false);
-
-            return ToOptimizedResult(result);
-        }
-
-        public async Task<object> Post(SyncData request)
-        {
-            var response = await _syncManager.SyncData(request).ConfigureAwait(false);
-
-            return ToOptimizedResult(response);
-        }
-
-        public void Post(UpdateSyncJob request)
-        {
-            var task = _syncManager.UpdateJob(request);
-
-            Task.WaitAll(task);
-        }
-
-        public Task<object> Get(GetSyncJobItemAdditionalFile request)
-        {
-            var jobItem = _syncManager.GetJobItem(request.Id);
-
-            if (jobItem.Status < SyncJobItemStatus.ReadyToTransfer)
-            {
-                throw new ArgumentException("The job item is not yet ready for transfer.");
-            }
-
-            var file = jobItem.AdditionalFiles.FirstOrDefault(i => string.Equals(i.Name, request.Name, StringComparison.OrdinalIgnoreCase));
-
-            if (file == null)
-            {
-                throw new ArgumentException("Sync job additional file not found.");
-            }
-
-            return ResultFactory.GetStaticFileResult(Request, file.Path);
-        }
-
-        public void Post(EnableSyncJobItem request)
-        {
-            var task = _syncManager.ReEnableJobItem(request.Id);
-
-            Task.WaitAll(task);
-        }
-
-        public void Delete(CancelSyncJobItem request)
-        {
-            var task = _syncManager.CancelJobItem(request.Id);
-
-            Task.WaitAll(task);
-        }
-
-        public void Post(MarkJobItemForRemoval request)
-        {
-            var task = _syncManager.MarkJobItemForRemoval(request.Id);
-
-            Task.WaitAll(task);
-        }
-
-        public void Post(UnmarkJobItemForRemoval request)
-        {
-            var task = _syncManager.UnmarkJobItemForRemoval(request.Id);
-
-            Task.WaitAll(task);
-        }
-    }
-}

+ 3 - 1
MediaBrowser.Common/Net/INetworkManager.cs

@@ -12,7 +12,9 @@ namespace MediaBrowser.Common.Net
         /// Gets a random port number that is currently available
         /// </summary>
         /// <returns>System.Int32.</returns>
-        int GetRandomUnusedPort();
+        int GetRandomUnusedTcpPort();
+
+        int GetRandomUnusedUdpPort();
 
         /// <summary>
         /// Returns MAC Address from first Network Card in Computer

+ 0 - 10
MediaBrowser.Controller/Entities/Folder.cs

@@ -756,11 +756,6 @@ namespace MediaBrowser.Controller.Entities
                     Logger.Debug("Query requires post-filtering due to ItemSortBy.AiredEpisodeOrder");
                     return true;
                 }
-                if (query.SortBy.Contains(ItemSortBy.Budget, StringComparer.OrdinalIgnoreCase))
-                {
-                    Logger.Debug("Query requires post-filtering due to ItemSortBy.Budget");
-                    return true;
-                }
                 if (query.SortBy.Contains(ItemSortBy.GameSystem, StringComparer.OrdinalIgnoreCase))
                 {
                     Logger.Debug("Query requires post-filtering due to ItemSortBy.GameSystem");
@@ -776,11 +771,6 @@ namespace MediaBrowser.Controller.Entities
                     Logger.Debug("Query requires post-filtering due to ItemSortBy.Players");
                     return true;
                 }
-                if (query.SortBy.Contains(ItemSortBy.Revenue, StringComparer.OrdinalIgnoreCase))
-                {
-                    Logger.Debug("Query requires post-filtering due to ItemSortBy.Revenue");
-                    return true;
-                }
                 if (query.SortBy.Contains(ItemSortBy.VideoBitRate, StringComparer.OrdinalIgnoreCase))
                 {
                     Logger.Debug("Query requires post-filtering due to ItemSortBy.VideoBitRate");

+ 0 - 18
MediaBrowser.Controller/Entities/IHasBudget.cs

@@ -1,18 +0,0 @@
-
-namespace MediaBrowser.Controller.Entities
-{
-    public interface IHasBudget
-    {
-        /// <summary>
-        /// Gets or sets the budget.
-        /// </summary>
-        /// <value>The budget.</value>
-        double? Budget { get; set; }
-
-        /// <summary>
-        /// Gets or sets the revenue.
-        /// </summary>
-        /// <value>The revenue.</value>
-        double? Revenue { get; set; }
-    }
-}

+ 1 - 13
MediaBrowser.Controller/Entities/Movies/Movie.cs

@@ -17,7 +17,7 @@ namespace MediaBrowser.Controller.Entities.Movies
     /// <summary>
     /// Class Movie
     /// </summary>
-    public class Movie : Video, IHasSpecialFeatures, IHasBudget, IHasTrailers, IHasAwards, IHasMetascore, IHasLookupInfo<MovieInfo>, ISupportsBoxSetGrouping
+    public class Movie : Video, IHasSpecialFeatures, IHasTrailers, IHasAwards, IHasMetascore, IHasLookupInfo<MovieInfo>, ISupportsBoxSetGrouping
     {
         public List<Guid> SpecialFeatureIds { get; set; }
 
@@ -45,18 +45,6 @@ namespace MediaBrowser.Controller.Entities.Movies
         /// <value>The taglines.</value>
         public List<string> Taglines { get; set; }
 
-        /// <summary>
-        /// Gets or sets the budget.
-        /// </summary>
-        /// <value>The budget.</value>
-        public double? Budget { get; set; }
-
-        /// <summary>
-        /// Gets or sets the revenue.
-        /// </summary>
-        /// <value>The revenue.</value>
-        public double? Revenue { get; set; }
-
         /// <summary>
         /// Gets or sets the name of the TMDB collection.
         /// </summary>

+ 1 - 12
MediaBrowser.Controller/Entities/MusicVideo.cs

@@ -6,19 +6,8 @@ using MediaBrowser.Model.Serialization;
 
 namespace MediaBrowser.Controller.Entities
 {
-    public class MusicVideo : Video, IHasArtist, IHasMusicGenres, IHasBudget, IHasLookupInfo<MusicVideoInfo>
+    public class MusicVideo : Video, IHasArtist, IHasMusicGenres, IHasLookupInfo<MusicVideoInfo>
     {
-        /// <summary>
-        /// Gets or sets the budget.
-        /// </summary>
-        /// <value>The budget.</value>
-        public double? Budget { get; set; }
-
-        /// <summary>
-        /// Gets or sets the revenue.
-        /// </summary>
-        /// <value>The revenue.</value>
-        public double? Revenue { get; set; }
         public List<string> Artists { get; set; }
 
         public MusicVideo()

+ 1 - 1
MediaBrowser.Controller/LiveTv/LiveTvChannel.cs

@@ -93,7 +93,7 @@ namespace MediaBrowser.Controller.LiveTv
 
                 if (double.TryParse(Number, NumberStyles.Any, CultureInfo.InvariantCulture, out number))
                 {
-                    return number.ToString("00000-") + (Name ?? string.Empty);
+                    return string.Format("{0:00000.0}", number) + "-" + (Name ?? string.Empty);
                 }
             }
 

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

@@ -109,7 +109,6 @@
     <Compile Include="Entities\GameGenre.cs" />
     <Compile Include="Entities\GameSystem.cs" />
     <Compile Include="Entities\IHasAspectRatio.cs" />
-    <Compile Include="Entities\IHasBudget.cs" />
     <Compile Include="Entities\IHasDisplayOrder.cs" />
     <Compile Include="Entities\IHasId.cs" />
     <Compile Include="Entities\IHasImages.cs" />

+ 0 - 8
MediaBrowser.Controller/MediaEncoding/IMediaEncoder.cs

@@ -78,14 +78,6 @@ namespace MediaBrowser.Controller.MediaEncoding
         /// <returns>Task.</returns>
         Task<MediaInfo> GetMediaInfo(MediaInfoRequest request, CancellationToken cancellationToken);
 
-        /// <summary>
-        /// Gets the probe size argument.
-        /// </summary>
-        /// <param name="inputFiles">The input files.</param>
-        /// <param name="protocol">The protocol.</param>
-        /// <returns>System.String.</returns>
-        string GetProbeSizeAndAnalyzeDurationArgument(string[] inputFiles, MediaProtocol protocol);
-
         /// <summary>
         /// Gets the input argument.
         /// </summary>

+ 1 - 1
MediaBrowser.Controller/MediaEncoding/MediaInfoRequest.cs

@@ -15,7 +15,7 @@ namespace MediaBrowser.Controller.MediaEncoding
         public IIsoMount MountedIso { get; set; }
         public VideoType VideoType { get; set; }
         public List<string> PlayableStreamFileNames { get; set; }
-        public int AnalyzeDurationSections { get; set; }
+        public int AnalyzeDurationMs { get; set; }
 
         public MediaInfoRequest()
         {

+ 1 - 1
MediaBrowser.LocalMetadata/Images/LocalImageProvider.cs

@@ -177,7 +177,7 @@ namespace MediaBrowser.LocalMetadata.Images
                 "default"
             };
 
-            if (item is MusicAlbum || item is MusicArtist || item is PhotoAlbum)
+            if (item is MusicAlbum || item is MusicArtist || item is PhotoAlbum || item is Person)
             {
                 // these prefer folder
                 names.Insert(0, "poster");

+ 0 - 32
MediaBrowser.LocalMetadata/Parsers/BaseItemXmlParser.cs

@@ -207,38 +207,6 @@ namespace MediaBrowser.LocalMetadata.Parsers
                         break;
                     }
 
-                case "Budget":
-                    {
-                        var text = reader.ReadElementContentAsString();
-                        var hasBudget = item as IHasBudget;
-                        if (hasBudget != null)
-                        {
-                            double value;
-                            if (double.TryParse(text, NumberStyles.Any, _usCulture, out value))
-                            {
-                                hasBudget.Budget = value;
-                            }
-                        }
-
-                        break;
-                    }
-
-                case "Revenue":
-                    {
-                        var text = reader.ReadElementContentAsString();
-                        var hasBudget = item as IHasBudget;
-                        if (hasBudget != null)
-                        {
-                            double value;
-                            if (double.TryParse(text, NumberStyles.Any, _usCulture, out value))
-                            {
-                                hasBudget.Revenue = value;
-                            }
-                        }
-
-                        break;
-                    }
-
                 case "Metascore":
                     {
                         var text = reader.ReadElementContentAsString();

+ 0 - 16
MediaBrowser.LocalMetadata/Savers/BaseXmlSaver.cs

@@ -37,7 +37,6 @@ namespace MediaBrowser.LocalMetadata.Savers
                     "AudioDbArtistId",
                     "AwardSummary",
                     "BirthDate",
-                    "Budget",
                     
                     // Deprecated. No longer saving in this field.
                     "certification",
@@ -90,7 +89,6 @@ namespace MediaBrowser.LocalMetadata.Savers
                     "PremiereDate",
                     "ProductionYear",
                     "Rating",
-                    "Revenue",
                     "RottenTomatoesId",
                     "RunningTime",
                     
@@ -435,20 +433,6 @@ namespace MediaBrowser.LocalMetadata.Savers
                 writer.WriteElementString("AwardSummary", hasAwards.AwardSummary);
             }
 
-            var hasBudget = item as IHasBudget;
-            if (hasBudget != null)
-            {
-                if (hasBudget.Budget.HasValue)
-                {
-                    writer.WriteElementString("Budget", hasBudget.Budget.Value.ToString(UsCulture));
-                }
-
-                if (hasBudget.Revenue.HasValue)
-                {
-                    writer.WriteElementString("Revenue", hasBudget.Revenue.Value.ToString(UsCulture));
-                }
-            }
-
             if (item.CommunityRating.HasValue)
             {
                 writer.WriteElementString("Rating", item.CommunityRating.Value.ToString(UsCulture));

+ 6 - 1
MediaBrowser.MediaEncoding/Encoder/EncoderValidator.cs

@@ -90,6 +90,7 @@ namespace MediaBrowser.MediaEncoding.Encoder
             var required = new[]
             {
                 "h264_qsv",
+                "hevc_qsv",
                 "mpeg2_qsv",
                 "vc1_qsv"
             };
@@ -134,9 +135,13 @@ namespace MediaBrowser.MediaEncoding.Encoder
                 "libvorbis",
                 "srt",
                 "h264_nvenc",
+                "hevc_nvenc",
                 "h264_qsv",
+                "hevc_qsv",
                 "h264_omx",
+                "hevc_omx",
                 "h264_vaapi",
+                "hevc_vaapi",
                 "ac3"
             };
 
@@ -205,4 +210,4 @@ namespace MediaBrowser.MediaEncoding.Encoder
             }
         }
     }
-}
+}

+ 0 - 10
MediaBrowser.MediaEncoding/Encoder/EncodingUtils.cs

@@ -61,15 +61,5 @@ namespace MediaBrowser.MediaEncoding.Encoder
             // Quotes are valid path characters in linux and they need to be escaped here with a leading \
             return path.Replace("\"", "\\\"");
         }
-
-        public static string GetProbeSizeArgument(int numInputFiles)
-        {
-            return numInputFiles > 1 ? "-probesize 1G" : "";
-        }
-
-        public static string GetAnalyzeDurationArgument(int numInputFiles)
-        {
-            return numInputFiles > 1 ? "-analyzeduration 200M" : "";
-        }
     }
 }

+ 22 - 35
MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs

@@ -523,17 +523,17 @@ namespace MediaBrowser.MediaEncoding.Encoder
 
             var inputFiles = MediaEncoderHelpers.GetInputArgument(FileSystem, request.InputPath, request.Protocol, request.MountedIso, request.PlayableStreamFileNames);
 
-            var probeSize = EncodingUtils.GetProbeSizeArgument(inputFiles.Length);
+            var probeSize = EncodingHelper.GetProbeSizeArgument(inputFiles.Length);
             string analyzeDuration;
 
-            if (request.AnalyzeDurationSections > 0)
+            if (request.AnalyzeDurationMs > 0)
             {
                 analyzeDuration = "-analyzeduration " +
-                                  (request.AnalyzeDurationSections * 1000000).ToString(CultureInfo.InvariantCulture);
+                                  (request.AnalyzeDurationMs * 1000).ToString(CultureInfo.InvariantCulture);
             }
             else
             {
-                analyzeDuration = EncodingUtils.GetAnalyzeDurationArgument(inputFiles.Length);
+                analyzeDuration = EncodingHelper.GetAnalyzeDurationArgument(inputFiles.Length);
             }
 
             probeSize = probeSize + " " + analyzeDuration;
@@ -557,31 +557,6 @@ namespace MediaBrowser.MediaEncoding.Encoder
             return EncodingUtils.GetInputArgument(inputFiles.ToList(), protocol);
         }
 
-        /// <summary>
-        /// Gets the probe size argument.
-        /// </summary>
-        /// <param name="inputFiles">The input files.</param>
-        /// <param name="protocol">The protocol.</param>
-        /// <returns>System.String.</returns>
-        public string GetProbeSizeAndAnalyzeDurationArgument(string[] inputFiles, MediaProtocol protocol)
-        {
-            var results = new List<string>();
-
-            var probeSize = EncodingUtils.GetProbeSizeArgument(inputFiles.Length);
-            var analyzeDuration = EncodingUtils.GetAnalyzeDurationArgument(inputFiles.Length);
-
-            if (!string.IsNullOrWhiteSpace(probeSize))
-            {
-                results.Add(probeSize);
-            }
-
-            if (!string.IsNullOrWhiteSpace(analyzeDuration))
-            {
-                results.Add(analyzeDuration);
-            }
-            return string.Join(" ", results.ToArray());
-        }
-
         /// <summary>
         /// Gets the media info internal.
         /// </summary>
@@ -984,11 +959,17 @@ namespace MediaBrowser.MediaEncoding.Encoder
             var args = useIFrame ? string.Format("-i {0}{3} -threads 0 -v quiet -vframes 1 -vf \"{2}{4}\" -f image2 \"{1}\"", inputPath, tempExtractPath, vf, mapArg, thumbnail) :
                 string.Format("-i {0}{3} -threads 0 -v quiet -vframes 1 -vf \"{2}\" -f image2 \"{1}\"", inputPath, tempExtractPath, vf, mapArg);
 
-            var probeSize = GetProbeSizeAndAnalyzeDurationArgument(new[] { inputPath }, protocol);
+            var probeSizeArgument = EncodingHelper.GetProbeSizeArgument(1);
+            var analyzeDurationArgument = EncodingHelper.GetAnalyzeDurationArgument(1);
+
+            if (!string.IsNullOrWhiteSpace(probeSizeArgument))
+            {
+                args = probeSizeArgument + " " + args;
+            }
 
-            if (!string.IsNullOrEmpty(probeSize))
+            if (!string.IsNullOrWhiteSpace(analyzeDurationArgument))
             {
-                args = probeSize + " " + args;
+                args = analyzeDurationArgument + " " + args;
             }
 
             if (offset.HasValue)
@@ -1092,11 +1073,17 @@ namespace MediaBrowser.MediaEncoding.Encoder
 
             var args = string.Format("-i {0} -threads 0 -v quiet -vf \"{2}\" -f image2 \"{1}\"", inputArgument, outputPath, vf);
 
-            var probeSize = GetProbeSizeAndAnalyzeDurationArgument(new[] { inputArgument }, protocol);
+            var probeSizeArgument = EncodingHelper.GetProbeSizeArgument(1);
+            var analyzeDurationArgument = EncodingHelper.GetAnalyzeDurationArgument(1);
+
+            if (!string.IsNullOrWhiteSpace(probeSizeArgument))
+            {
+                args = probeSizeArgument + " " + args;
+            }
 
-            if (!string.IsNullOrEmpty(probeSize))
+            if (!string.IsNullOrWhiteSpace(analyzeDurationArgument))
             {
-                args = probeSize + " " + args;
+                args = analyzeDurationArgument + " " + args;
             }
 
             var process = _processFactory.Create(new ProcessOptions

+ 26 - 3
MediaBrowser.MediaEncoding/Probing/ProbeResultNormalizer.cs

@@ -558,13 +558,36 @@ namespace MediaBrowser.MediaEncoding.Probing
                     ? MediaStreamType.EmbeddedImage
                     : MediaStreamType.Video;
 
+                stream.AverageFrameRate = GetFrameRate(streamInfo.avg_frame_rate);
+                stream.RealFrameRate = GetFrameRate(streamInfo.r_frame_rate);
+
+                if (isAudio || string.Equals(stream.Codec, "gif", StringComparison.OrdinalIgnoreCase) ||
+                    string.Equals(stream.Codec, "png", StringComparison.OrdinalIgnoreCase))
+                {
+                    stream.Type = MediaStreamType.EmbeddedImage;
+                }
+                else if (string.Equals(stream.Codec, "mjpeg", StringComparison.OrdinalIgnoreCase))
+                {
+                    // How to differentiate between video and embedded image?
+                    // The only difference I've seen thus far is presence of codec tag, also embedded images have high (unusual) framerates 
+                    if (!string.IsNullOrWhiteSpace(stream.CodecTag))
+                    {
+                        stream.Type = MediaStreamType.Video;
+                    }
+                    else
+                    {
+                        stream.Type = MediaStreamType.EmbeddedImage;
+                    }
+                }
+                else
+                {
+                    stream.Type = MediaStreamType.Video;
+                }
+
                 stream.Width = streamInfo.width;
                 stream.Height = streamInfo.height;
                 stream.AspectRatio = GetAspectRatio(streamInfo);
 
-                stream.AverageFrameRate = GetFrameRate(streamInfo.avg_frame_rate);
-                stream.RealFrameRate = GetFrameRate(streamInfo.r_frame_rate);
-
                 if (streamInfo.bits_per_sample > 0)
                 {
                     stream.BitDepth = streamInfo.bits_per_sample;

+ 11 - 6
MediaBrowser.MediaEncoding/Subtitles/SubtitleEncoder.cs

@@ -734,6 +734,16 @@ namespace MediaBrowser.MediaEncoding.Subtitles
                 }
             }
 
+            var charsetFromLanguage = string.IsNullOrWhiteSpace(language)
+                ? null
+                : GetSubtitleFileCharacterSetFromLanguage(language);
+
+            // This assumption should only be made for external subtitles
+            if (!string.IsNullOrWhiteSpace(charsetFromLanguage) && !string.Equals(charsetFromLanguage, "windows-1252", StringComparison.OrdinalIgnoreCase))
+            {
+                return charsetFromLanguage;
+            }
+
             var charset = await DetectCharset(path, language, protocol, cancellationToken).ConfigureAwait(false);
 
             if (!string.IsNullOrWhiteSpace(charset))
@@ -746,12 +756,7 @@ namespace MediaBrowser.MediaEncoding.Subtitles
                 return charset;
             }
 
-            if (!string.IsNullOrWhiteSpace(language))
-            {
-                return GetSubtitleFileCharacterSetFromLanguage(language);
-            }
-
-            return null;
+            return charsetFromLanguage;
         }
 
         public string GetSubtitleFileCharacterSetFromLanguage(string language)

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

@@ -827,72 +827,6 @@ namespace MediaBrowser.Model.Dto
             get { return StringHelper.EqualsIgnoreCase(MediaType, Entities.MediaType.Video); }
         }
 
-        /// <summary>
-        /// Gets a value indicating whether this instance is audio.
-        /// </summary>
-        /// <value><c>true</c> if this instance is audio; otherwise, <c>false</c>.</value>
-        [IgnoreDataMember]
-        public bool IsAudio
-        {
-            get { return StringHelper.EqualsIgnoreCase(MediaType, Entities.MediaType.Audio); }
-        }
-
-        /// <summary>
-        /// Gets a value indicating whether this instance is game.
-        /// </summary>
-        /// <value><c>true</c> if this instance is game; otherwise, <c>false</c>.</value>
-        [IgnoreDataMember]
-        public bool IsGame
-        {
-            get { return StringHelper.EqualsIgnoreCase(MediaType, Entities.MediaType.Game); }
-        }
-
-        /// <summary>
-        /// Gets a value indicating whether this instance is person.
-        /// </summary>
-        /// <value><c>true</c> if this instance is person; otherwise, <c>false</c>.</value>
-        [IgnoreDataMember]
-        public bool IsPerson
-        {
-            get { return StringHelper.EqualsIgnoreCase(Type, "Person"); }
-        }
-
-        [IgnoreDataMember]
-        public bool IsMusicGenre
-        {
-            get { return StringHelper.EqualsIgnoreCase(Type, "MusicGenre"); }
-        }
-
-        [IgnoreDataMember]
-        public bool IsGameGenre
-        {
-            get { return StringHelper.EqualsIgnoreCase(Type, "GameGenre"); }
-        }
-
-        [IgnoreDataMember]
-        public bool IsGenre
-        {
-            get { return StringHelper.EqualsIgnoreCase(Type, "Genre"); }
-        }
-
-        [IgnoreDataMember]
-        public bool IsArtist
-        {
-            get { return StringHelper.EqualsIgnoreCase(Type, "MusicArtist"); }
-        }
-
-        [IgnoreDataMember]
-        public bool IsAlbum
-        {
-            get { return StringHelper.EqualsIgnoreCase(Type, "MusicAlbum"); }
-        }
-
-        [IgnoreDataMember]
-        public bool IsStudio
-        {
-            get { return StringHelper.EqualsIgnoreCase(Type, "Studio"); }
-        }
-
         /// <summary>
         /// Gets or sets the program identifier.
         /// </summary>

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

@@ -60,6 +60,8 @@ namespace MediaBrowser.Model.Dto
         public string TranscodingSubProtocol { get; set; }
         public string TranscodingContainer { get; set; }
 
+        public int? AnalyzeDurationMs { get; set; }
+
         public MediaSourceInfo()
         {
             Formats = new List<string>();

+ 3 - 1
MediaBrowser.Model/Dto/UserDto.cs

@@ -89,7 +89,9 @@ namespace MediaBrowser.Model.Dto
         /// </summary>
         /// <value><c>true</c> if this instance has configured easy password; otherwise, <c>false</c>.</value>
         public bool HasConfiguredEasyPassword { get; set; }
-        
+
+        public bool? EnableAutoLogin { get; set; }
+
         /// <summary>
         /// Gets or sets the last login date.
         /// </summary>

+ 1 - 0
MediaBrowser.Model/LiveTv/LiveTvOptions.cs

@@ -36,6 +36,7 @@ namespace MediaBrowser.Model.LiveTv
             MediaLocationsCreated = new string[] { };
             RecordingEncodingFormat = "mp4";
             RecordingPostProcessorArguments = "\"{path}\"";
+            EnableRecordingEncoding = true;
         }
     }
 

+ 2 - 2
MediaBrowser.Model/MediaBrowser.Model.csproj

@@ -137,9 +137,9 @@
     <Compile Include="Dto\NameValuePair.cs" />
     <Compile Include="Logging\IConsoleLogger.cs" />
     <Compile Include="Net\IpEndPointInfo.cs" />
-    <Compile Include="Net\ISocket.cs" />
+    <Compile Include="Net\IAcceptSocket.cs" />
     <Compile Include="Net\ISocketFactory.cs" />
-    <Compile Include="Net\IUdpSocket.cs" />
+    <Compile Include="Net\ISocket.cs" />
     <Compile Include="Net\SocketReceiveResult.cs" />
     <Compile Include="Services\IHttpResult.cs" />
     <Compile Include="Social\ISharingRepository.cs" />

+ 28 - 0
MediaBrowser.Model/Net/IAcceptSocket.cs

@@ -0,0 +1,28 @@
+using System;
+
+namespace MediaBrowser.Model.Net
+{
+    public interface IAcceptSocket : IDisposable
+    {
+        bool DualMode { get; }
+        IpEndPointInfo LocalEndPoint { get; }
+        IpEndPointInfo RemoteEndPoint { get; }
+        void Close();
+        void Shutdown(bool both);
+        void Listen(int backlog);
+        void Bind(IpEndPointInfo endpoint);
+        void Connect(IpEndPointInfo endPoint);
+        void StartAccept(Action<IAcceptSocket> 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; }
+    }
+}

+ 19 - 19
MediaBrowser.Model/Net/ISocket.cs

@@ -1,28 +1,28 @@
 using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading;
+using System.Threading.Tasks;
 
 namespace MediaBrowser.Model.Net
 {
+    /// <summary>
+    /// Provides a common interface across platforms for UDP sockets used by this SSDP implementation.
+    /// </summary>
     public interface ISocket : IDisposable
     {
-        bool DualMode { get; }
-        IpEndPointInfo LocalEndPoint { get; }
-        IpEndPointInfo RemoteEndPoint { get; }
-        void Close();
-        void Shutdown(bool both);
-        void Listen(int backlog);
-        void Bind(IpEndPointInfo endpoint);
+        IpAddressInfo LocalIPAddress { get; }
 
-        void StartAccept(Action<ISocket> onAccept, Func<bool> isClosed);
-    }
-
-    public class SocketCreateException : Exception
-    {
-        public SocketCreateException(string errorCode, Exception originalException)
-            : base(errorCode, originalException)
-        {
-            ErrorCode = errorCode;
-        }
+        /// <summary>
+        /// Waits for and returns the next UDP message sent to this socket (uni or multicast).
+        /// </summary>
+        /// <returns></returns>
+        Task<SocketReceiveResult> ReceiveAsync(CancellationToken cancellationToken);
 
-        public string ErrorCode { get; private set; }
+        /// <summary>
+        /// Sends a UDP message to a particular end point (uni or multicast).
+        /// </summary>
+        Task SendAsync(byte[] buffer, int bytes, IpEndPointInfo endPoint, CancellationToken cancellationToken);
     }
-}
+}

+ 9 - 7
MediaBrowser.Model/Net/ISocketFactory.cs

@@ -2,7 +2,7 @@
 namespace MediaBrowser.Model.Net
 {
     /// <summary>
-    /// Implemented by components that can create a platform specific UDP socket implementation, and wrap it in the cross platform <see cref="IUdpSocket"/> interface.
+    /// Implemented by components that can create a platform specific UDP socket implementation, and wrap it in the cross platform <see cref="ISocket"/> interface.
     /// </summary>
     public interface ISocketFactory
 	{
@@ -11,13 +11,15 @@ namespace MediaBrowser.Model.Net
 		/// Createa a new unicast socket using the specified local port number.
 		/// </summary>
 		/// <param name="localPort">The local port to bind to.</param>
-		/// <returns>A <see cref="IUdpSocket"/> implementation.</returns>
-		IUdpSocket CreateUdpSocket(int localPort);
+		/// <returns>A <see cref="ISocket"/> implementation.</returns>
+		ISocket CreateUdpSocket(int localPort);
+
+        ISocket CreateTcpSocket(IpAddressInfo remoteAddress, int remotePort);
 
         /// <summary>
         /// Createa a new unicast socket using the specified local port number.
         /// </summary>
-        IUdpSocket CreateSsdpUdpSocket(IpAddressInfo localIp, int localPort);
+        ISocket CreateSsdpUdpSocket(IpAddressInfo localIp, int localPort);
 
         /// <summary>
         /// Createa a new multicast socket using the specified multicast IP address, multicast time to live and local port.
@@ -25,10 +27,10 @@ namespace MediaBrowser.Model.Net
         /// <param name="ipAddress">The multicast IP address to bind to.</param>
         /// <param name="multicastTimeToLive">The multicast time to live value. Actually a maximum number of network hops for UDP packets.</param>
         /// <param name="localPort">The local port to bind to.</param>
-        /// <returns>A <see cref="IUdpSocket"/> implementation.</returns>
-        IUdpSocket CreateUdpMulticastSocket(string ipAddress, int multicastTimeToLive, int localPort);
+        /// <returns>A <see cref="ISocket"/> implementation.</returns>
+        ISocket CreateUdpMulticastSocket(string ipAddress, int multicastTimeToLive, int localPort);
 
-        ISocket CreateSocket(IpAddressFamily family, SocketType socketType, ProtocolType protocolType, bool dualMode);
+        IAcceptSocket CreateSocket(IpAddressFamily family, SocketType socketType, ProtocolType protocolType, bool dualMode);
     }
 
     public enum SocketType

+ 0 - 28
MediaBrowser.Model/Net/IUdpSocket.cs

@@ -1,28 +0,0 @@
-using System;
-using System.Collections.Generic;
-using System.Linq;
-using System.Text;
-using System.Threading;
-using System.Threading.Tasks;
-
-namespace MediaBrowser.Model.Net
-{
-    /// <summary>
-    /// Provides a common interface across platforms for UDP sockets used by this SSDP implementation.
-    /// </summary>
-    public interface IUdpSocket : IDisposable
-    {
-        IpAddressInfo LocalIPAddress { get; }
-
-        /// <summary>
-        /// Waits for and returns the next UDP message sent to this socket (uni or multicast).
-        /// </summary>
-        /// <returns></returns>
-        Task<SocketReceiveResult> ReceiveAsync();
-
-        /// <summary>
-        /// Sends a UDP message to a particular end point (uni or multicast).
-        /// </summary>
-        Task SendAsync(byte[] buffer, int bytes, IpEndPointInfo endPoint, CancellationToken cancellationToken);
-    }
-}

+ 3 - 0
MediaBrowser.Model/Net/MimeTypes.cs

@@ -322,6 +322,9 @@ namespace MediaBrowser.Model.Net
                 throw new ArgumentNullException("mimeType");
             }
 
+            // handle text/html; charset=UTF-8
+            mimeType = mimeType.Split(';')[0];
+
             string result;
             if (ExtensionLookup.TryGetValue(mimeType, out result))
             {

+ 2 - 10
MediaBrowser.Model/Querying/ItemFields.cs

@@ -20,11 +20,6 @@
         /// </summary>
         AwardSummary,
 
-        /// <summary>
-        /// The budget
-        /// </summary>
-        Budget,
-
         /// <summary>
         /// The can delete
         /// </summary>
@@ -156,6 +151,8 @@
         /// </summary>
         People,
 
+        PlayAccess,
+
         /// <summary>
         /// The production locations
         /// </summary>
@@ -173,11 +170,6 @@
 
         RecursiveItemCount,
 
-        /// <summary>
-        /// The revenue
-        /// </summary>
-        Revenue,
-
         /// <summary>
         /// The season name
         /// </summary>

+ 0 - 8
MediaBrowser.Model/Querying/ItemSortBy.cs

@@ -20,14 +20,6 @@ namespace MediaBrowser.Model.Querying
         /// </summary>
         public const string Artist = "Artist";
         /// <summary>
-        /// The budget
-        /// </summary>
-        public const string Budget = "Budget";
-        /// <summary>
-        /// The revenue
-        /// </summary>
-        public const string Revenue = "Revenue";
-        /// <summary>
         /// The date created
         /// </summary>
         public const string DateCreated = "DateCreated";

+ 4 - 0
MediaBrowser.Model/Session/PlaybackProgressInfo.cs

@@ -73,6 +73,10 @@ namespace MediaBrowser.Model.Session
         /// <value>The volume level.</value>
         public int? VolumeLevel { get; set; }
 
+        public int? Brightness { get; set; }
+
+        public string AspectRatio { get; set; }
+
         /// <summary>
         /// Gets or sets the play method.
         /// </summary>

+ 1 - 0
MediaBrowser.Providers/Manager/ImageSaver.cs

@@ -410,6 +410,7 @@ namespace MediaBrowser.Providers.Manager
             var folderName = item is MusicAlbum ||
                 item is MusicArtist ||
                 item is PhotoAlbum ||
+                item is Person ||
                 (saveLocally && _config.Configuration.ImageSavingConvention == ImageSavingConvention.Legacy) ?
                 "folder" :
                 "poster";

+ 0 - 20
MediaBrowser.Providers/Manager/ProviderUtils.cs

@@ -195,7 +195,6 @@ namespace MediaBrowser.Providers.Manager
             }
 
             MergeAlbumArtist(source, target, lockedFields, replaceData);
-            MergeBudget(source, target, lockedFields, replaceData);
             MergeMetascore(source, target, lockedFields, replaceData);
             MergeCriticRating(source, target, lockedFields, replaceData);
             MergeAwards(source, target, lockedFields, replaceData);
@@ -247,25 +246,6 @@ namespace MediaBrowser.Providers.Manager
             }
         }
 
-        private static void MergeBudget(BaseItem source, BaseItem target, List<MetadataFields> lockedFields, bool replaceData)
-        {
-            var sourceHasBudget = source as IHasBudget;
-            var targetHasBudget = target as IHasBudget;
-
-            if (sourceHasBudget != null && targetHasBudget != null)
-            {
-                if (replaceData || !targetHasBudget.Budget.HasValue)
-                {
-                    targetHasBudget.Budget = sourceHasBudget.Budget;
-                }
-
-                if (replaceData || !targetHasBudget.Revenue.HasValue)
-                {
-                    targetHasBudget.Revenue = sourceHasBudget.Revenue;
-                }
-            }
-        }
-
         private static void MergeMetascore(BaseItem source, BaseItem target, List<MetadataFields> lockedFields, bool replaceData)
         {
             var sourceCast = source as IHasMetascore;

+ 0 - 7
MediaBrowser.Providers/Movies/GenericMovieDbInfo.cs

@@ -136,13 +136,6 @@ namespace MediaBrowser.Providers.Movies
 
             movie.HomePageUrl = movieData.homepage;
 
-            var hasBudget = movie as IHasBudget;
-            if (hasBudget != null)
-            {
-                hasBudget.Budget = movieData.budget;
-                hasBudget.Revenue = movieData.revenue;
-            }
-
             if (!string.IsNullOrEmpty(movieData.tagline))
             {
                 movie.Tagline = movieData.tagline;

+ 0 - 5
MediaBrowser.Providers/TV/TheTVDB/TvdbSeriesProvider.cs

@@ -170,11 +170,6 @@ namespace MediaBrowser.Providers.TV
         /// <exception cref="System.ArgumentNullException">seriesId</exception>
         internal async Task DownloadSeriesZip(string seriesId, string idType, string seriesDataPath, long? lastTvDbUpdateTime, string preferredMetadataLanguage, CancellationToken cancellationToken)
         {
-            if (string.IsNullOrWhiteSpace(seriesId))
-            {
-                throw new ArgumentNullException("seriesId");
-            }
-
             try
             {
                 await DownloadSeriesZip(seriesId, idType, seriesDataPath, lastTvDbUpdateTime, preferredMetadataLanguage, preferredMetadataLanguage, cancellationToken).ConfigureAwait(false);

+ 9 - 15
MediaBrowser.Server.Mac/Emby.Server.Mac.csproj

@@ -329,9 +329,6 @@
     <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\favicon.ico">
       <Link>Resources\dashboard-ui\favicon.ico</Link>
     </BundleResource>
-    <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\favorites.html">
-      <Link>Resources\dashboard-ui\favorites.html</Link>
-    </BundleResource>
     <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\forgotpassword.html">
       <Link>Resources\dashboard-ui\forgotpassword.html</Link>
     </BundleResource>
@@ -665,9 +662,6 @@
     <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\emby-apiclient\localassetmanager.js">
       <Link>Resources\dashboard-ui\bower_components\emby-apiclient\localassetmanager.js</Link>
     </BundleResource>
-    <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\emby-apiclient\nullassetmanager.js">
-      <Link>Resources\dashboard-ui\bower_components\emby-apiclient\nullassetmanager.js</Link>
-    </BundleResource>
     <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\emby-apiclient\serverdiscovery-chrome.js">
       <Link>Resources\dashboard-ui\bower_components\emby-apiclient\serverdiscovery-chrome.js</Link>
     </BundleResource>
@@ -698,9 +692,6 @@
     <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\emby-apiclient\sync\multiserversync.js">
       <Link>Resources\dashboard-ui\bower_components\emby-apiclient\sync\multiserversync.js</Link>
     </BundleResource>
-    <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\emby-apiclient\sync\offlineusersync.js">
-      <Link>Resources\dashboard-ui\bower_components\emby-apiclient\sync\offlineusersync.js</Link>
-    </BundleResource>
     <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\emby-apiclient\sync\serversync.js">
       <Link>Resources\dashboard-ui\bower_components\emby-apiclient\sync\serversync.js</Link>
     </BundleResource>
@@ -710,9 +701,6 @@
     <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\emby-apiclient\sync\useractionrepository.js">
       <Link>Resources\dashboard-ui\bower_components\emby-apiclient\sync\useractionrepository.js</Link>
     </BundleResource>
-    <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\emby-apiclient\sync\userrepository.js">
-      <Link>Resources\dashboard-ui\bower_components\emby-apiclient\sync\userrepository.js</Link>
-    </BundleResource>
     <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\emby-webcomponents\appsettings.js">
       <Link>Resources\dashboard-ui\bower_components\emby-webcomponents\appsettings.js</Link>
     </BundleResource>
@@ -1205,6 +1193,9 @@
     <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\emby-webcomponents\playback\autoplaydetect.js">
       <Link>Resources\dashboard-ui\bower_components\emby-webcomponents\playback\autoplaydetect.js</Link>
     </BundleResource>
+    <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\emby-webcomponents\playback\brightnessosd.js">
+      <Link>Resources\dashboard-ui\bower_components\emby-webcomponents\playback\brightnessosd.js</Link>
+    </BundleResource>
     <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\emby-webcomponents\playback\iconosd.css">
       <Link>Resources\dashboard-ui\bower_components\emby-webcomponents\playback\iconosd.css</Link>
     </BundleResource>
@@ -1214,6 +1205,9 @@
     <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\emby-webcomponents\playback\nowplayinghelper.js">
       <Link>Resources\dashboard-ui\bower_components\emby-webcomponents\playback\nowplayinghelper.js</Link>
     </BundleResource>
+    <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\emby-webcomponents\playback\playaccessvalidation.js">
+      <Link>Resources\dashboard-ui\bower_components\emby-webcomponents\playback\playaccessvalidation.js</Link>
+    </BundleResource>
     <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\emby-webcomponents\playback\playbackmanager.js">
       <Link>Resources\dashboard-ui\bower_components\emby-webcomponents\playback\playbackmanager.js</Link>
     </BundleResource>
@@ -1886,6 +1880,9 @@
     <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\css\site.css">
       <Link>Resources\dashboard-ui\css\site.css</Link>
     </BundleResource>
+    <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\css\videoosd.css">
+      <Link>Resources\dashboard-ui\css\videoosd.css</Link>
+    </BundleResource>
     <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\css\images\ani_equalizer_black.gif">
       <Link>Resources\dashboard-ui\css\images\ani_equalizer_black.gif</Link>
     </BundleResource>
@@ -2228,9 +2225,6 @@
     <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\scripts\episodes.js">
       <Link>Resources\dashboard-ui\scripts\episodes.js</Link>
     </BundleResource>
-    <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\scripts\favorites.js">
-      <Link>Resources\dashboard-ui\scripts\favorites.js</Link>
-    </BundleResource>
     <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\scripts\forgotpassword.js">
       <Link>Resources\dashboard-ui\scripts\forgotpassword.js</Link>
     </BundleResource>

+ 3 - 0
MediaBrowser.Server.Mono/MediaBrowser.Server.Mono.csproj

@@ -61,6 +61,9 @@
     <Reference Include="Emby.Common.Implementations">
       <HintPath>..\ThirdParty\emby\Emby.Common.Implementations.dll</HintPath>
     </Reference>
+    <Reference Include="Emby.Server.CinemaMode">
+      <HintPath>..\ThirdParty\emby\Emby.Server.CinemaMode.dll</HintPath>
+    </Reference>
     <Reference Include="Emby.Server.Connect">
       <HintPath>..\ThirdParty\emby\Emby.Server.Connect.dll</HintPath>
     </Reference>

+ 2 - 0
MediaBrowser.Server.Mono/MonoAppHost.cs

@@ -1,6 +1,7 @@
 using System;
 using System.Collections.Generic;
 using System.Reflection;
+using Emby.Server.CinemaMode;
 using Emby.Server.Connect;
 using Emby.Server.Core;
 using Emby.Server.Implementations;
@@ -58,6 +59,7 @@ namespace MediaBrowser.Server.Mono
         {
             var list = new List<Assembly>();
 
+            list.Add(typeof(DefaultIntroProvider).Assembly);
             list.Add(typeof(LinuxIsoManager).Assembly);
             list.Add(typeof(ConnectManager).Assembly);
             list.Add(typeof(SyncManager).Assembly);

+ 0 - 105
MediaBrowser.Server.Startup.Common/LiveTv/TunerHosts/SatIp/ChannelScan.cs

@@ -1,105 +0,0 @@
-using System;
-using System.Collections.Generic;
-using System.Globalization;
-using System.IO;
-using System.Linq;
-using System.Threading;
-using System.Threading.Tasks;
-using IniParser;
-using IniParser.Model;
-using MediaBrowser.Controller.LiveTv;
-using MediaBrowser.Model.LiveTv;
-using MediaBrowser.Model.Logging;
-using MediaBrowser.Server.Implementations.LiveTv.TunerHosts.SatIp.Rtsp;
-
-namespace MediaBrowser.Server.Implementations.LiveTv.TunerHosts.SatIp
-{
-    public class ChannelScan
-    {
-        private readonly ILogger _logger;
-
-        public ChannelScan(ILogger logger)
-        {
-            _logger = logger;
-        }
-
-        public async Task<List<ChannelInfo>> Scan(TunerHostInfo info, CancellationToken cancellationToken)
-        {
-            var ini = info.SourceA.Split('|')[1];
-            var resource = GetType().Assembly.GetManifestResourceNames().FirstOrDefault(i => i.EndsWith(ini, StringComparison.OrdinalIgnoreCase));
-
-            _logger.Info("Opening ini file {0}", resource);
-            var list = new List<ChannelInfo>();
-
-            using (var stream = GetType().Assembly.GetManifestResourceStream(resource))
-            {
-                using (var reader = new StreamReader(stream))
-                {
-                    var parser = new StreamIniDataParser();
-                    var data = parser.ReadData(reader);
-
-                    var count = GetInt(data, "DVB", "0", 0);
-
-                    _logger.Info("DVB Count: {0}", count);
-
-                    var index = 1;
-                    var source = "1";
-
-                    while (index <= count)
-                    {
-                        cancellationToken.ThrowIfCancellationRequested();
-
-                        using (var rtspSession = new RtspSession(info.Url, _logger))
-                        {
-                            float percent = count == 0 ? 0 : (float)(index) / count;
-                            percent = Math.Max(percent * 100, 100);
-
-                            //SetControlPropertyThreadSafe(pgbSearchResult, "Value", (int)percent);
-                            var strArray = data["DVB"][index.ToString(CultureInfo.InvariantCulture)].Split(',');
-
-                            string tuning;
-                            if (strArray[4] == "S2")
-                            {
-                                tuning = string.Format("src={0}&freq={1}&pol={2}&sr={3}&fec={4}&msys=dvbs2&mtype={5}&plts=on&ro=0.35&pids=0,16,17,18,20", source, strArray[0], strArray[1].ToLower(), strArray[2].ToLower(), strArray[3], strArray[5].ToLower());
-                            }
-                            else
-                            {
-                                tuning = string.Format("src={0}&freq={1}&pol={2}&sr={3}&fec={4}&msys=dvbs&mtype={5}&pids=0,16,17,18,20", source, strArray[0], strArray[1].ToLower(), strArray[2], strArray[3], strArray[5].ToLower());
-                            }
-
-                            rtspSession.Setup(tuning, "unicast");
-
-                            rtspSession.Play(string.Empty);
-
-                            int signallevel;
-                            int signalQuality;
-                            rtspSession.Describe(out signallevel, out signalQuality);
-
-                            await Task.Delay(500).ConfigureAwait(false);
-                            index++;
-                        }
-                    }
-                }
-            }
-
-            return list;
-        }
-
-        private int GetInt(IniData data, string s1, string s2, int defaultValue)
-        {
-            var value = data[s1][s2];
-            int numericValue;
-            if (int.TryParse(value, NumberStyles.Any, CultureInfo.InvariantCulture, out numericValue))
-            {
-                return numericValue;
-            }
-
-            return defaultValue;
-        }
-    }
-
-    public class SatChannel
-    {
-        // TODO: Add properties
-    }
-}

+ 0 - 79
MediaBrowser.Server.Startup.Common/LiveTv/TunerHosts/SatIp/Rtcp/ReportBlock.cs

@@ -1,79 +0,0 @@
-/*  
-    Copyright (C) <2007-2016>  <Kay Diefenthal>
-
-    SatIp.RtspSample is free software: you can redistribute it and/or modify
-    it under the terms of the GNU General Public License as published by
-    the Free Software Foundation, either version 3 of the License, or
-    (at your option) any later version.
-
-    SatIp.RtspSample is distributed in the hope that it will be useful,
-    but WITHOUT ANY WARRANTY; without even the implied warranty of
-    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-    GNU General Public License for more details.
-
-    You should have received a copy of the GNU General Public License
-    along with SatIp.RtspSample.  If not, see <http://www.gnu.org/licenses/>.
-*/
-
-namespace MediaBrowser.Server.Implementations.LiveTv.TunerHosts.SatIp.Rtcp
-{
-    public class ReportBlock
-    {
-        /// <summary>
-        /// Get the length of the block.
-        /// </summary>
-        public int BlockLength { get { return (24); } }
-        /// <summary>
-        /// Get the synchronization source.
-        /// </summary>
-        public string SynchronizationSource { get; private set; }
-        /// <summary>
-        /// Get the fraction lost.
-        /// </summary>
-        public int FractionLost { get; private set; }
-        /// <summary>
-        /// Get the cumulative packets lost.
-        /// </summary>
-        public int CumulativePacketsLost { get; private set; }
-        /// <summary>
-        /// Get the highest number received.
-        /// </summary>
-        public int HighestNumberReceived { get; private set; }
-        /// <summary>
-        /// Get the inter arrival jitter.
-        /// </summary>
-        public int InterArrivalJitter { get; private set; }
-        /// <summary>
-        /// Get the timestamp of the last report.
-        /// </summary>
-        public int LastReportTimeStamp { get; private set; }
-        /// <summary>
-        /// Get the delay since the last report.
-        /// </summary>
-        public int DelaySinceLastReport { get; private set; }
-
-        /// <summary>
-        /// Initialize a new instance of the ReportBlock class.
-        /// </summary>
-        public ReportBlock() { }
-
-        /// <summary>
-        /// Unpack the data in a packet.
-        /// </summary>
-        /// <param name="buffer">The buffer containing the packet.</param>
-        /// <param name="offset">The offset to the first byte of the packet within the buffer.</param>
-        /// <returns>An ErrorSpec instance if an error occurs; null otherwise.</returns>
-        public void Process(byte[] buffer, int offset)
-        {
-            SynchronizationSource = Utils.ConvertBytesToString(buffer, offset, 4);
-            FractionLost = buffer[offset + 4];
-            CumulativePacketsLost = Utils.Convert3BytesToInt(buffer, offset + 5);
-            HighestNumberReceived = Utils.Convert4BytesToInt(buffer, offset + 8);
-            InterArrivalJitter = Utils.Convert4BytesToInt(buffer, offset + 12);
-            LastReportTimeStamp = Utils.Convert4BytesToInt(buffer, offset + 16);
-            DelaySinceLastReport = Utils.Convert4BytesToInt(buffer, offset + 20);
-
-            
-        }
-    }
-}

+ 0 - 68
MediaBrowser.Server.Startup.Common/LiveTv/TunerHosts/SatIp/Rtcp/RtcpAppPacket.cs

@@ -1,68 +0,0 @@
-/*  
-    Copyright (C) <2007-2016>  <Kay Diefenthal>
-
-    SatIp.RtspSample is free software: you can redistribute it and/or modify
-    it under the terms of the GNU General Public License as published by
-    the Free Software Foundation, either version 3 of the License, or
-    (at your option) any later version.
-
-    SatIp.RtspSample is distributed in the hope that it will be useful,
-    but WITHOUT ANY WARRANTY; without even the implied warranty of
-    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-    GNU General Public License for more details.
-
-    You should have received a copy of the GNU General Public License
-    along with SatIp.RtspSample.  If not, see <http://www.gnu.org/licenses/>.
-*/
-using System.Text;
-
-namespace MediaBrowser.Server.Implementations.LiveTv.TunerHosts.SatIp.Rtcp
-{
-    class RtcpAppPacket : RtcpPacket
-    {
-        /// <summary>
-        /// Get the synchronization source.
-        /// </summary>
-        public int SynchronizationSource { get; private set; }
-        /// <summary>
-        /// Get the name.
-        /// </summary>
-        public string Name { get; private set; }
-        /// <summary>
-        /// Get the identity.
-        /// </summary>
-        public int Identity { get; private set; }
-        /// <summary>
-        /// Get the variable data portion.
-        /// </summary>
-        public string Data { get; private set; }
-
-        public override void Parse(byte[] buffer, int offset)
-        {
-            base.Parse(buffer, offset);
-            SynchronizationSource = Utils.Convert4BytesToInt(buffer, offset + 4);
-            Name = Utils.ConvertBytesToString(buffer, offset + 8, 4);
-            Identity = Utils.Convert2BytesToInt(buffer, offset + 12);
-
-            int dataLength = Utils.Convert2BytesToInt(buffer, offset + 14);
-            if (dataLength != 0)
-                Data = Utils.ConvertBytesToString(buffer, offset + 16, dataLength);
-        }
-        public override string ToString()
-        {
-            StringBuilder sb = new StringBuilder();
-            sb.AppendFormat("Application Specific.\n");
-            sb.AppendFormat("Version : {0} .\n", Version);
-            sb.AppendFormat("Padding : {0} .\n", Padding);
-            sb.AppendFormat("Report Count : {0} .\n", ReportCount);
-            sb.AppendFormat("PacketType: {0} .\n", Type);
-            sb.AppendFormat("Length : {0} .\n", Length);
-            sb.AppendFormat("SynchronizationSource : {0} .\n", SynchronizationSource);
-            sb.AppendFormat("Name : {0} .\n", Name);
-            sb.AppendFormat("Identity : {0} .\n", Identity);
-            sb.AppendFormat("Data : {0} .\n", Data);            
-            sb.AppendFormat(".\n");
-            return sb.ToString();
-        }
-    }
-}

+ 0 - 59
MediaBrowser.Server.Startup.Common/LiveTv/TunerHosts/SatIp/Rtcp/RtcpByePacket.cs

@@ -1,59 +0,0 @@
-using System.Collections.ObjectModel;
-/*  
-    Copyright (C) <2007-2016>  <Kay Diefenthal>
-
-    SatIp.RtspSample is free software: you can redistribute it and/or modify
-    it under the terms of the GNU General Public License as published by
-    the Free Software Foundation, either version 3 of the License, or
-    (at your option) any later version.
-
-    SatIp.RtspSample is distributed in the hope that it will be useful,
-    but WITHOUT ANY WARRANTY; without even the implied warranty of
-    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-    GNU General Public License for more details.
-
-    You should have received a copy of the GNU General Public License
-    along with SatIp.RtspSample.  If not, see <http://www.gnu.org/licenses/>.
-*/
-using System.Text;
-
-namespace MediaBrowser.Server.Implementations.LiveTv.TunerHosts.SatIp.Rtcp
-{
-    public class RtcpByePacket :RtcpPacket
-    {
-        public Collection<string> SynchronizationSources { get; private set; }
-        public string ReasonForLeaving { get; private set; }
-        public override void Parse(byte[] buffer, int offset)
-        {
-            base.Parse(buffer, offset);
-            SynchronizationSources = new Collection<string>();
-            int index = 4;
-
-            while (SynchronizationSources.Count < ReportCount)
-            {
-                SynchronizationSources.Add(Utils.ConvertBytesToString(buffer, offset + index, 4));
-                index += 4;
-            }
-
-            if (index < Length)
-            {
-                int reasonLength = buffer[offset + index];
-                ReasonForLeaving = Utils.ConvertBytesToString(buffer, offset + index + 1, reasonLength);
-            }
-        }
-        public override string ToString()
-        {
-            StringBuilder sb = new StringBuilder();
-            sb.AppendFormat("ByeBye .\n");
-            sb.AppendFormat("Version : {0} .\n", Version);
-            sb.AppendFormat("Padding : {0} .\n", Padding);
-            sb.AppendFormat("Report Count : {0} .\n", ReportCount);
-            sb.AppendFormat("PacketType: {0} .\n", Type);
-            sb.AppendFormat("Length : {0} .\n", Length);
-            sb.AppendFormat("SynchronizationSources : {0} .\n", SynchronizationSources);
-            sb.AppendFormat("ReasonForLeaving : {0} .\n", ReasonForLeaving);            
-            sb.AppendFormat(".\n");
-            return sb.ToString();
-        }
-    }
-}

+ 0 - 203
MediaBrowser.Server.Startup.Common/LiveTv/TunerHosts/SatIp/Rtcp/RtcpListener.cs

@@ -1,203 +0,0 @@
-/*  
-    Copyright (C) <2007-2016>  <Kay Diefenthal>
-
-    SatIp.RtspSample is free software: you can redistribute it and/or modify
-    it under the terms of the GNU General Public License as published by
-    the Free Software Foundation, either version 3 of the License, or
-    (at your option) any later version.
-
-    SatIp.RtspSample is distributed in the hope that it will be useful,
-    but WITHOUT ANY WARRANTY; without even the implied warranty of
-    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-    GNU General Public License for more details.
-
-    You should have received a copy of the GNU General Public License
-    along with SatIp.RtspSample.  If not, see <http://www.gnu.org/licenses/>.
-*/
-using System;
-using System.Net;
-using System.Net.Sockets;
-using System.Threading;
-using MediaBrowser.Model.Logging;
-
-namespace MediaBrowser.Server.Implementations.LiveTv.TunerHosts.SatIp.Rtcp
-{
-    public class RtcpListener
-    {
-	private readonly ILogger _logger;
-        private Thread _rtcpListenerThread;
-        private AutoResetEvent _rtcpListenerThreadStopEvent = null;
-        private UdpClient _udpClient;
-        private IPEndPoint _multicastEndPoint;
-        private IPEndPoint _serverEndPoint;
-        private TransmissionMode _transmissionMode;
-
-        public RtcpListener(String address, int port, TransmissionMode mode,ILogger logger)
-        {
-            _logger = logger;
-            _transmissionMode = mode;
-            switch (mode)
-            {
-                case TransmissionMode.Unicast:
-                    _udpClient = new UdpClient(new IPEndPoint(IPAddress.Parse(address), port));
-                    _serverEndPoint = new IPEndPoint(IPAddress.Any, 0);
-                    break;
-                case TransmissionMode.Multicast:
-                    _multicastEndPoint = new IPEndPoint(IPAddress.Parse(address), port);
-                    _serverEndPoint = new IPEndPoint(IPAddress.Any, 0);
-                    _udpClient = new UdpClient();
-                    _udpClient.Client.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, 1);
-                    _udpClient.ExclusiveAddressUse = false;
-                    _udpClient.Client.Bind(new IPEndPoint(IPAddress.Any, port));
-                    _udpClient.JoinMulticastGroup(_multicastEndPoint.Address);
-                    break;
-            }
-            //StartRtcpListenerThread();
-        }
-
-        public void StartRtcpListenerThread()
-        {
-            // Kill the existing thread if it is in "zombie" state.
-            if (_rtcpListenerThread != null && !_rtcpListenerThread.IsAlive)
-            {
-                StopRtcpListenerThread();
-            }
-
-            if (_rtcpListenerThread == null)
-            {
-                _logger.Info("SAT>IP : starting new RTCP listener thread");
-                _rtcpListenerThreadStopEvent = new AutoResetEvent(false);
-                _rtcpListenerThread = new Thread(new ThreadStart(RtcpListenerThread));
-                _rtcpListenerThread.Name = string.Format("SAT>IP tuner  RTCP listener");
-                _rtcpListenerThread.IsBackground = true;
-                _rtcpListenerThread.Priority = ThreadPriority.Lowest;
-                _rtcpListenerThread.Start();
-            }
-        }
-
-        public void StopRtcpListenerThread()
-        {
-            if (_rtcpListenerThread != null)
-            {
-                if (!_rtcpListenerThread.IsAlive)
-                {
-                    _logger.Info("SAT>IP : aborting old RTCP listener thread");
-                    _rtcpListenerThread.Abort();
-                }
-                else
-                {
-                    _rtcpListenerThreadStopEvent.Set();
-                    if (!_rtcpListenerThread.Join(400 * 2))
-                    {
-                        _logger.Info("SAT>IP : failed to join RTCP listener thread, aborting thread");
-                        _rtcpListenerThread.Abort();
-                    }
-                }
-                _rtcpListenerThread = null;
-                if (_rtcpListenerThreadStopEvent != null)
-                {
-                    _rtcpListenerThreadStopEvent.Close();
-                    _rtcpListenerThreadStopEvent = null;
-                }
-            }
-        }
-
-        private void RtcpListenerThread()
-        {
-            try
-            {               
-                bool receivedGoodBye = false;                
-                try
-                {
-                    _udpClient.Client.ReceiveTimeout = 400;
-                    IPEndPoint serverEndPoint = new IPEndPoint(IPAddress.Any, 0);
-                    while (!receivedGoodBye && !_rtcpListenerThreadStopEvent.WaitOne(1))
-                    {
-                        byte[] packets = _udpClient.Receive(ref serverEndPoint);
-                        if (packets == null)
-                        {
-                            continue;
-                        }
-                        
-                        int offset = 0;
-                        while (offset < packets.Length)
-                        {
-                            switch (packets[offset + 1])
-                            {
-                                case 200: //sr
-                                    var sr = new RtcpSenderReportPacket();
-                                    sr.Parse(packets, offset);                                    
-                                    offset += sr.Length;
-                                    break;
-                                case 201: //rr
-                                    var rr = new RtcpReceiverReportPacket();
-                                    rr.Parse(packets, offset);                                    
-                                    offset += rr.Length;
-                                    break;
-                                case 202: //sd
-                                    var sd = new RtcpSourceDescriptionPacket();
-                                    sd.Parse(packets, offset);                                    
-                                    offset += sd.Length;
-                                    break;
-                                case 203: // bye
-                                    var bye = new RtcpByePacket();
-                                    bye.Parse(packets, offset);                                    
-                                    receivedGoodBye = true;
-                                    OnPacketReceived(new RtcpPacketReceivedArgs(bye));
-                                    offset += bye.Length;                                    
-                                    break;
-                                case 204: // app
-                                    var app = new RtcpAppPacket();
-                                    app.Parse(packets, offset);                                    
-                                    OnPacketReceived(new RtcpPacketReceivedArgs(app));
-                                    offset += app.Length;
-                                    break;
-                            }                           
-                        }
-                        
-                    }
-                }
-                finally
-                {
-                    switch (_transmissionMode)
-                    {
-                        case TransmissionMode.Multicast:
-                            _udpClient.DropMulticastGroup(_multicastEndPoint.Address);
-                            _udpClient.Close();
-                            break;
-                        case TransmissionMode.Unicast:
-                            _udpClient.Close();
-                            break;
-                    }   
-                }
-            }
-            catch (ThreadAbortException)
-            {
-            }
-            catch (Exception ex)
-            {
-                _logger.Info(string.Format("SAT>IP : RTCP listener thread exception"), ex);
-                return;
-            }
-            _logger.Info("SAT>IP : RTCP listener thread stopping");
-        }
-        public delegate void PacketReceivedHandler(object sender, RtcpPacketReceivedArgs e);
-        public event PacketReceivedHandler PacketReceived;
-        public class RtcpPacketReceivedArgs : EventArgs
-        {
-            public Object Packet { get; private set; }
-
-            public RtcpPacketReceivedArgs(Object packet)
-            {
-                Packet = packet;
-            }
-        }
-        protected void OnPacketReceived(RtcpPacketReceivedArgs args)
-        {
-            if (PacketReceived != null)
-            {
-                PacketReceived(this, args);
-            }
-        }
-    }
-}

+ 0 - 37
MediaBrowser.Server.Startup.Common/LiveTv/TunerHosts/SatIp/Rtcp/RtcpPacket.cs

@@ -1,37 +0,0 @@
-/*  
-    Copyright (C) <2007-2016>  <Kay Diefenthal>
-
-    SatIp.RtspSample is free software: you can redistribute it and/or modify
-    it under the terms of the GNU General Public License as published by
-    the Free Software Foundation, either version 3 of the License, or
-    (at your option) any later version.
-
-    SatIp.RtspSample is distributed in the hope that it will be useful,
-    but WITHOUT ANY WARRANTY; without even the implied warranty of
-    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-    GNU General Public License for more details.
-
-    You should have received a copy of the GNU General Public License
-    along with SatIp.RtspSample.  If not, see <http://www.gnu.org/licenses/>.
-*/
-
-namespace MediaBrowser.Server.Implementations.LiveTv.TunerHosts.SatIp.Rtcp
-{
-    public abstract class RtcpPacket
-    {
-        public int Version { get; private set; }
-        public bool Padding { get; private set; }
-        public int ReportCount { get; private set; }
-        public int Type { get; private set; }
-        public int Length { get; private set; }        
-
-        public virtual void Parse(byte[] buffer, int offset)
-        {
-            Version = buffer[offset] >> 6;
-            Padding = (buffer[offset] & 0x20) != 0;
-            ReportCount = buffer[offset] & 0x1f;
-            Type = buffer[offset + 1];
-            Length = (Utils.Convert2BytesToInt(buffer, offset + 2) * 4) + 4;             
-        }
-    }
-}

+ 0 - 68
MediaBrowser.Server.Startup.Common/LiveTv/TunerHosts/SatIp/Rtcp/RtcpReceiverReportPacket.cs

@@ -1,68 +0,0 @@
-using System.Collections.ObjectModel;
-/*  
-    Copyright (C) <2007-2016>  <Kay Diefenthal>
-
-    SatIp.RtspSample is free software: you can redistribute it and/or modify
-    it under the terms of the GNU General Public License as published by
-    the Free Software Foundation, either version 3 of the License, or
-    (at your option) any later version.
-
-    SatIp.RtspSample is distributed in the hope that it will be useful,
-    but WITHOUT ANY WARRANTY; without even the implied warranty of
-    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-    GNU General Public License for more details.
-
-    You should have received a copy of the GNU General Public License
-    along with SatIp.RtspSample.  If not, see <http://www.gnu.org/licenses/>.
-*/
-using System.Text;
-
-namespace MediaBrowser.Server.Implementations.LiveTv.TunerHosts.SatIp.Rtcp
-{
-    public class RtcpReceiverReportPacket :RtcpPacket
-    {
-        public string SynchronizationSource { get; private set; }
-        public Collection<ReportBlock> ReportBlocks { get; private set; }
-        public byte[] ProfileExtension { get; private set; }
-        public override void Parse(byte[] buffer, int offset)
-        {
-            base.Parse(buffer, offset);
-            SynchronizationSource = Utils.ConvertBytesToString(buffer, offset + 4, 4);
-
-            ReportBlocks = new Collection<ReportBlock>();
-            int index = 8;
-
-            while (ReportBlocks.Count < ReportCount)
-            {
-                ReportBlock reportBlock = new ReportBlock();
-                reportBlock.Process(buffer, offset + index);
-                ReportBlocks.Add(reportBlock);
-                index += reportBlock.BlockLength;
-            }
-
-            if (index < Length)
-            {
-                ProfileExtension = new byte[Length - index];
-
-                for (int extensionIndex = 0; index < Length; index++)
-                {
-                    ProfileExtension[extensionIndex] = buffer[offset + index];
-                    extensionIndex++;
-                }
-            }
-        }
-        public override string ToString()
-        {
-            StringBuilder sb = new StringBuilder();
-            sb.AppendFormat("Receiver Report.\n");
-            sb.AppendFormat("Version : {0} .\n", Version);
-            sb.AppendFormat("Padding : {0} .\n", Padding);
-            sb.AppendFormat("Report Count : {0} .\n", ReportCount);
-            sb.AppendFormat("PacketType: {0} .\n", Type);
-            sb.AppendFormat("Length : {0} .\n", Length);
-            sb.AppendFormat("SynchronizationSource : {0} .\n", SynchronizationSource);            
-            sb.AppendFormat(".\n");
-            return sb.ToString();
-        }
-    }
-}

Vissa filer visades inte eftersom för många filer har ändrats