Browse Source

Merge pull request #1098 from MediaBrowser/dev

3.0.5607.0
Luke 10 năm trước cách đây
mục cha
commit
b2cbe8b4e1
100 tập tin đã thay đổi với 1131 bổ sung894 xóa
  1. 1 3
      MediaBrowser.Api/Images/ImageService.cs
  2. 2 51
      MediaBrowser.Api/Library/LibraryService.cs
  3. 12 31
      MediaBrowser.Api/Playback/BaseStreamingService.cs
  4. 2 1
      MediaBrowser.Api/Playback/Dash/MpegDashService.cs
  5. 2 1
      MediaBrowser.Api/Playback/Hls/BaseHlsService.cs
  6. 2 1
      MediaBrowser.Api/Playback/Hls/DynamicHlsService.cs
  7. 2 1
      MediaBrowser.Api/Playback/Hls/VideoHlsService.cs
  8. 23 14
      MediaBrowser.Api/Playback/MediaInfoService.cs
  9. 2 1
      MediaBrowser.Api/Playback/Progressive/AudioService.cs
  10. 2 1
      MediaBrowser.Api/Playback/Progressive/BaseProgressiveStreamingService.cs
  11. 2 1
      MediaBrowser.Api/Playback/Progressive/VideoService.cs
  12. 1 0
      MediaBrowser.Api/Subtitles/SubtitleService.cs
  13. 4 7
      MediaBrowser.Common.Implementations/MediaBrowser.Common.Implementations.csproj
  14. 13 30
      MediaBrowser.Common.Implementations/Networking/BaseNetworkManager.cs
  15. 2 2
      MediaBrowser.Common.Implementations/packages.config
  16. 9 0
      MediaBrowser.Controller/Dlna/ISsdpHandler.cs
  17. 2 1
      MediaBrowser.Controller/Dlna/SsdpMessageEventArgs.cs
  18. 8 30
      MediaBrowser.Controller/Entities/Audio/Audio.cs
  19. 0 47
      MediaBrowser.Controller/Entities/Audio/MusicAlbum.cs
  20. 0 32
      MediaBrowser.Controller/Entities/BaseItem.cs
  21. 0 23
      MediaBrowser.Controller/Entities/TV/Episode.cs
  22. 1 43
      MediaBrowser.Controller/Entities/TV/Season.cs
  23. 0 13
      MediaBrowser.Controller/Entities/TV/Series.cs
  24. 12 0
      MediaBrowser.Controller/Entities/User.cs
  25. 1 3
      MediaBrowser.Controller/Entities/UserViewBuilder.cs
  26. 2 0
      MediaBrowser.Controller/MediaBrowser.Controller.csproj
  27. 1 0
      MediaBrowser.Dlna/Channels/DlnaChannelFactory.cs
  28. 0 4
      MediaBrowser.Dlna/Didl/DidlBuilder.cs
  29. 4 2
      MediaBrowser.Dlna/DlnaManager.cs
  30. 18 38
      MediaBrowser.Dlna/Main/DlnaEntryPoint.cs
  31. 6 1
      MediaBrowser.Dlna/MediaBrowser.Dlna.csproj
  32. 8 8
      MediaBrowser.Dlna/PlayTo/Device.cs
  33. 4 3
      MediaBrowser.Dlna/PlayTo/PlayToController.cs
  34. 82 49
      MediaBrowser.Dlna/PlayTo/PlayToManager.cs
  35. 8 8
      MediaBrowser.Dlna/PlayTo/SsdpHttpClient.cs
  36. 76 0
      MediaBrowser.Dlna/Profiles/BubbleUpnpProfile.cs
  37. 18 0
      MediaBrowser.Dlna/Profiles/DefaultProfile.cs
  38. 1 8
      MediaBrowser.Dlna/Profiles/PanasonicVieraProfile.cs
  39. 1 8
      MediaBrowser.Dlna/Profiles/SamsungSmartTvProfile.cs
  40. 1 8
      MediaBrowser.Dlna/Profiles/SonyBlurayPlayer2013Profile.cs
  41. 1 8
      MediaBrowser.Dlna/Profiles/SonyBlurayPlayerProfile.cs
  42. 8 8
      MediaBrowser.Dlna/Profiles/SonyBravia2010Profile.cs
  43. 8 8
      MediaBrowser.Dlna/Profiles/SonyBravia2011Profile.cs
  44. 8 8
      MediaBrowser.Dlna/Profiles/SonyBravia2012Profile.cs
  45. 8 8
      MediaBrowser.Dlna/Profiles/SonyBravia2013Profile.cs
  46. 76 0
      MediaBrowser.Dlna/Profiles/VlcProfile.cs
  47. 0 1
      MediaBrowser.Dlna/Profiles/WdtvLiveProfile.cs
  48. 7 3
      MediaBrowser.Dlna/Profiles/Xbox360Profile.cs
  49. 1 1
      MediaBrowser.Dlna/Profiles/XboxOneProfile.cs
  50. 29 0
      MediaBrowser.Dlna/Profiles/Xml/BubbleUPnp.xml
  51. 4 2
      MediaBrowser.Dlna/Profiles/Xml/Default.xml
  52. 4 2
      MediaBrowser.Dlna/Profiles/Xml/Denon AVR.xml
  53. 4 2
      MediaBrowser.Dlna/Profiles/Xml/DirecTV HD-DVR.xml
  54. 4 2
      MediaBrowser.Dlna/Profiles/Xml/Dish Hopper-Joey.xml
  55. 23 0
      MediaBrowser.Dlna/Profiles/Xml/Generic Device.xml
  56. 4 2
      MediaBrowser.Dlna/Profiles/Xml/LG Smart TV.xml
  57. 4 2
      MediaBrowser.Dlna/Profiles/Xml/Linksys DMA2100.xml
  58. 4 2
      MediaBrowser.Dlna/Profiles/Xml/MediaMonkey.xml
  59. 2 1
      MediaBrowser.Dlna/Profiles/Xml/Panasonic Viera.xml
  60. 4 2
      MediaBrowser.Dlna/Profiles/Xml/Popcorn Hour.xml
  61. 2 1
      MediaBrowser.Dlna/Profiles/Xml/Samsung Smart TV.xml
  62. 2 1
      MediaBrowser.Dlna/Profiles/Xml/Sony Blu-ray Player 2013.xml
  63. 2 1
      MediaBrowser.Dlna/Profiles/Xml/Sony Blu-ray Player.xml
  64. 4 2
      MediaBrowser.Dlna/Profiles/Xml/Sony Bravia (2010).xml
  65. 4 2
      MediaBrowser.Dlna/Profiles/Xml/Sony Bravia (2011).xml
  66. 4 2
      MediaBrowser.Dlna/Profiles/Xml/Sony Bravia (2012).xml
  67. 4 2
      MediaBrowser.Dlna/Profiles/Xml/Sony Bravia (2013).xml
  68. 4 2
      MediaBrowser.Dlna/Profiles/Xml/Sony PlayStation 3.xml
  69. 29 0
      MediaBrowser.Dlna/Profiles/Xml/Vlc.xml
  70. 4 2
      MediaBrowser.Dlna/Profiles/Xml/WDTV Live.xml
  71. 6 6
      MediaBrowser.Dlna/Profiles/Xml/Xbox 360.xml
  72. 5 3
      MediaBrowser.Dlna/Profiles/Xml/Xbox One.xml
  73. 4 2
      MediaBrowser.Dlna/Profiles/Xml/foobar2000.xml
  74. 26 7
      MediaBrowser.Dlna/Server/DescriptionXmlBuilder.cs
  75. 4 2
      MediaBrowser.Dlna/Service/BaseControlHandler.cs
  76. 57 21
      MediaBrowser.Dlna/Ssdp/Datagram.cs
  77. 18 9
      MediaBrowser.Dlna/Ssdp/DeviceDiscovery.cs
  78. 114 30
      MediaBrowser.Dlna/Ssdp/SsdpHandler.cs
  79. 4 2
      MediaBrowser.Dlna/Ssdp/SsdpHelper.cs
  80. 3 25
      MediaBrowser.MediaEncoding/Encoder/BaseEncoder.cs
  81. 0 2
      MediaBrowser.MediaEncoding/Encoder/EncodingJobFactory.cs
  82. 160 136
      MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs
  83. 0 2
      MediaBrowser.MediaEncoding/Encoder/VideoEncoder.cs
  84. 6 0
      MediaBrowser.Model/ApiClient/IApiClient.cs
  85. 2 4
      MediaBrowser.Model/Configuration/ServerConfiguration.cs
  86. 3 1
      MediaBrowser.Model/Configuration/UserConfiguration.cs
  87. 26 1
      MediaBrowser.Model/Dlna/CodecProfile.cs
  88. 0 6
      MediaBrowser.Model/Dlna/ConditionProcessor.cs
  89. 2 5
      MediaBrowser.Model/Dlna/ContentFeatureBuilder.cs
  90. 1 4
      MediaBrowser.Model/Dlna/DeviceProfile.cs
  91. 8 8
      MediaBrowser.Model/Dlna/StreamBuilder.cs
  92. 14 16
      MediaBrowser.Providers/Manager/ItemImageProvider.cs
  93. 9 0
      MediaBrowser.Providers/Manager/ProviderUtils.cs
  94. 1 1
      MediaBrowser.Providers/MediaInfo/AudioImageProvider.cs
  95. 11 4
      MediaBrowser.Providers/TV/TvdbEpisodeProvider.cs
  96. 1 10
      MediaBrowser.Server.Implementations/Dto/DtoService.cs
  97. 23 5
      MediaBrowser.Server.Implementations/EntryPoints/ExternalPortForwarding.cs
  98. 1 2
      MediaBrowser.Server.Implementations/FileOrganization/EpisodeFileOrganizer.cs
  99. 4 4
      MediaBrowser.Server.Implementations/IO/LibraryMonitor.cs
  100. 21 25
      MediaBrowser.Server.Implementations/Library/LibraryManager.cs

+ 1 - 3
MediaBrowser.Api/Images/ImageService.cs

@@ -648,10 +648,8 @@ namespace MediaBrowser.Api.Images
 
 
             var serverFormats = _imageProcessor.GetSupportedImageOutputFormats();
             var serverFormats = _imageProcessor.GetSupportedImageOutputFormats();
 
 
-            var clientFormats = GetClientSupportedFormats();
-
             if (serverFormats.Contains(ImageFormat.Webp) &&
             if (serverFormats.Contains(ImageFormat.Webp) &&
-                clientFormats.Contains(ImageFormat.Webp))
+                GetClientSupportedFormats().Contains(ImageFormat.Webp))
             {
             {
                 return ImageFormat.Webp;
                 return ImageFormat.Webp;
             }
             }

+ 2 - 51
MediaBrowser.Api/Library/LibraryService.cs

@@ -617,36 +617,14 @@ namespace MediaBrowser.Api.Library
                                   : (Folder)_libraryManager.RootFolder)
                                   : (Folder)_libraryManager.RootFolder)
                            : _libraryManager.GetItemById(request.Id);
                            : _libraryManager.GetItemById(request.Id);
 
 
-            var originalItem = item;
-
             while (GetThemeSongIds(item).Count == 0 && request.InheritFromParent && item.Parent != null)
             while (GetThemeSongIds(item).Count == 0 && request.InheritFromParent && item.Parent != null)
             {
             {
                 item = item.Parent;
                 item = item.Parent;
             }
             }
 
 
-            var themeSongIds = GetThemeSongIds(item);
-
-            if (themeSongIds.Count == 0 && request.InheritFromParent)
-            {
-                var album = originalItem as MusicAlbum;
-
-                if (album != null)
-                {
-                    var linkedItemWithThemes = album.SoundtrackIds
-                        .Select(i => _libraryManager.GetItemById(i))
-                        .FirstOrDefault(i => GetThemeSongIds(i).Count > 0);
-
-                    if (linkedItemWithThemes != null)
-                    {
-                        themeSongIds = GetThemeSongIds(linkedItemWithThemes);
-                        item = linkedItemWithThemes;
-                    }
-                }
-            }
-
             var dtoOptions = GetDtoOptions(request);
             var dtoOptions = GetDtoOptions(request);
 
 
-            var dtos = themeSongIds.Select(_libraryManager.GetItemById)
+            var dtos = GetThemeSongIds(item).Select(_libraryManager.GetItemById)
                             .OrderBy(i => i.SortName)
                             .OrderBy(i => i.SortName)
                             .Select(i => _dtoService.GetBaseItemDto(i, dtoOptions, user, item));
                             .Select(i => _dtoService.GetBaseItemDto(i, dtoOptions, user, item));
 
 
@@ -682,41 +660,14 @@ namespace MediaBrowser.Api.Library
                                   : (Folder)_libraryManager.RootFolder)
                                   : (Folder)_libraryManager.RootFolder)
                            : _libraryManager.GetItemById(request.Id);
                            : _libraryManager.GetItemById(request.Id);
 
 
-            var originalItem = item;
-
             while (GetThemeVideoIds(item).Count == 0 && request.InheritFromParent && item.Parent != null)
             while (GetThemeVideoIds(item).Count == 0 && request.InheritFromParent && item.Parent != null)
             {
             {
                 item = item.Parent;
                 item = item.Parent;
             }
             }
 
 
-            var themeVideoIds = GetThemeVideoIds(item);
-
-            if (themeVideoIds.Count == 0 && request.InheritFromParent)
-            {
-                var album = originalItem as MusicAlbum;
-
-                if (album == null)
-                {
-                    album = originalItem.Parents.OfType<MusicAlbum>().FirstOrDefault();
-                }
-
-                if (album != null)
-                {
-                    var linkedItemWithThemes = album.SoundtrackIds
-                        .Select(i => _libraryManager.GetItemById(i))
-                        .FirstOrDefault(i => GetThemeVideoIds(i).Count > 0);
-
-                    if (linkedItemWithThemes != null)
-                    {
-                        themeVideoIds = GetThemeVideoIds(linkedItemWithThemes);
-                        item = linkedItemWithThemes;
-                    }
-                }
-            }
-
             var dtoOptions = GetDtoOptions(request);
             var dtoOptions = GetDtoOptions(request);
 
 
-            var dtos = themeVideoIds.Select(_libraryManager.GetItemById)
+            var dtos = GetThemeVideoIds(item).Select(_libraryManager.GetItemById)
                             .OrderBy(i => i.SortName)
                             .OrderBy(i => i.SortName)
                             .Select(i => _dtoService.GetBaseItemDto(i, dtoOptions, user, item));
                             .Select(i => _dtoService.GetBaseItemDto(i, dtoOptions, user, item));
 
 

+ 12 - 31
MediaBrowser.Api/Playback/BaseStreamingService.cs

@@ -23,6 +23,7 @@ using System.Linq;
 using System.Text;
 using System.Text;
 using System.Threading;
 using System.Threading;
 using System.Threading.Tasks;
 using System.Threading.Tasks;
+using MediaBrowser.Model.Serialization;
 
 
 namespace MediaBrowser.Api.Playback
 namespace MediaBrowser.Api.Playback
 {
 {
@@ -68,12 +69,14 @@ namespace MediaBrowser.Api.Playback
         protected ISubtitleEncoder SubtitleEncoder { get; private set; }
         protected ISubtitleEncoder SubtitleEncoder { get; private set; }
         protected IMediaSourceManager MediaSourceManager { get; private set; }
         protected IMediaSourceManager MediaSourceManager { get; private set; }
         protected IZipClient ZipClient { get; private set; }
         protected IZipClient ZipClient { get; private set; }
+        protected IJsonSerializer JsonSerializer { get; private set; }
 
 
         /// <summary>
         /// <summary>
         /// Initializes a new instance of the <see cref="BaseStreamingService" /> class.
         /// Initializes a new instance of the <see cref="BaseStreamingService" /> class.
         /// </summary>
         /// </summary>
-        protected BaseStreamingService(IServerConfigurationManager serverConfig, IUserManager userManager, ILibraryManager libraryManager, IIsoManager isoManager, IMediaEncoder mediaEncoder, IFileSystem fileSystem, IDlnaManager dlnaManager, ISubtitleEncoder subtitleEncoder, IDeviceManager deviceManager, IMediaSourceManager mediaSourceManager, IZipClient zipClient)
+        protected BaseStreamingService(IServerConfigurationManager serverConfig, IUserManager userManager, ILibraryManager libraryManager, IIsoManager isoManager, IMediaEncoder mediaEncoder, IFileSystem fileSystem, IDlnaManager dlnaManager, ISubtitleEncoder subtitleEncoder, IDeviceManager deviceManager, IMediaSourceManager mediaSourceManager, IZipClient zipClient, IJsonSerializer jsonSerializer)
         {
         {
+            JsonSerializer = jsonSerializer;
             ZipClient = zipClient;
             ZipClient = zipClient;
             MediaSourceManager = mediaSourceManager;
             MediaSourceManager = mediaSourceManager;
             DeviceManager = deviceManager;
             DeviceManager = deviceManager;
@@ -598,7 +601,7 @@ namespace MediaBrowser.Api.Playback
                 var maxWidthParam = request.MaxWidth.Value.ToString(UsCulture);
                 var maxWidthParam = request.MaxWidth.Value.ToString(UsCulture);
                 var maxHeightParam = request.MaxHeight.Value.ToString(UsCulture);
                 var maxHeightParam = request.MaxHeight.Value.ToString(UsCulture);
 
 
-                filters.Add(string.Format("scale=trunc(min(iw\\,{0})/2)*2:trunc(min((iw/dar)\\,{1})/2)*2", maxWidthParam, maxHeightParam));
+                filters.Add(string.Format("scale=trunc(min(max(iw\\,ih*dar)\\,min({0}\\,{1}*dar))/2)*2:trunc(min(max(iw/dar\\,ih)\\,min({0}/dar\\,{1}))/2)*2", maxWidthParam, maxHeightParam));
             }
             }
 
 
             // If a fixed width was requested
             // If a fixed width was requested
@@ -618,7 +621,7 @@ namespace MediaBrowser.Api.Playback
             }
             }
 
 
             // If a max width was requested
             // If a max width was requested
-            else if (request.MaxWidth.HasValue && (!request.MaxHeight.HasValue || state.VideoStream == null))
+            else if (request.MaxWidth.HasValue)
             {
             {
                 var maxWidthParam = request.MaxWidth.Value.ToString(UsCulture);
                 var maxWidthParam = request.MaxWidth.Value.ToString(UsCulture);
 
 
@@ -626,35 +629,13 @@ namespace MediaBrowser.Api.Playback
             }
             }
 
 
             // If a max height was requested
             // If a max height was requested
-            else if (request.MaxHeight.HasValue && (!request.MaxWidth.HasValue || state.VideoStream == null))
+            else if (request.MaxHeight.HasValue)
             {
             {
                 var maxHeightParam = request.MaxHeight.Value.ToString(UsCulture);
                 var maxHeightParam = request.MaxHeight.Value.ToString(UsCulture);
 
 
                 filters.Add(string.Format("scale=trunc(oh*a*2)/2:min(ih\\,{0})", maxHeightParam));
                 filters.Add(string.Format("scale=trunc(oh*a*2)/2:min(ih\\,{0})", maxHeightParam));
             }
             }
 
 
-            else if (request.MaxWidth.HasValue ||
-                request.MaxHeight.HasValue ||
-                request.Width.HasValue ||
-                request.Height.HasValue)
-            {
-                if (state.VideoStream != null)
-                {
-                    // Need to perform calculations manually
-
-                    // Try to account for bad media info
-                    var currentHeight = state.VideoStream.Height ?? request.MaxHeight ?? request.Height ?? 0;
-                    var currentWidth = state.VideoStream.Width ?? request.MaxWidth ?? request.Width ?? 0;
-
-                    var outputSize = DrawingUtils.Resize(currentWidth, currentHeight, request.Width, request.Height, request.MaxWidth, request.MaxHeight);
-
-                    var manualWidthParam = outputSize.Width.ToString(UsCulture);
-                    var manualHeightParam = outputSize.Height.ToString(UsCulture);
-
-                    filters.Add(string.Format("scale=trunc({0}/2)*2:trunc({1}/2)*2", manualWidthParam, manualHeightParam));
-                }
-            }
-
             if (string.Equals(outputVideoCodec, "h264_qsv", StringComparison.OrdinalIgnoreCase))
             if (string.Equals(outputVideoCodec, "h264_qsv", StringComparison.OrdinalIgnoreCase))
             {
             {
                 filters[filters.Count - 1] += ":flags=fast_bilinear";
                 filters[filters.Count - 1] += ":flags=fast_bilinear";
@@ -1027,7 +1008,7 @@ namespace MediaBrowser.Api.Playback
             // FFMpeg writes debug/error info to stderr. This is useful when debugging so let's put it in the log directory.
             // FFMpeg writes debug/error info to stderr. This is useful when debugging so let's put it in the log directory.
             state.LogFileStream = FileSystem.GetFileStream(logFilePath, FileMode.Create, FileAccess.Write, FileShare.Read, true);
             state.LogFileStream = FileSystem.GetFileStream(logFilePath, FileMode.Create, FileAccess.Write, FileShare.Read, true);
 
 
-            var commandLineLogMessageBytes = Encoding.UTF8.GetBytes(Request.AbsoluteUri + Environment.NewLine + Environment.NewLine + commandLineLogMessage + Environment.NewLine + Environment.NewLine);
+            var commandLineLogMessageBytes = Encoding.UTF8.GetBytes(Request.AbsoluteUri + Environment.NewLine + Environment.NewLine + JsonSerializer.SerializeToString(state.MediaSource) + Environment.NewLine + Environment.NewLine + commandLineLogMessage + Environment.NewLine + Environment.NewLine);
             await state.LogFileStream.WriteAsync(commandLineLogMessageBytes, 0, commandLineLogMessageBytes.Length, cancellationTokenSource.Token).ConfigureAwait(false);
             await state.LogFileStream.WriteAsync(commandLineLogMessageBytes, 0, commandLineLogMessageBytes.Length, cancellationTokenSource.Token).ConfigureAwait(false);
 
 
             process.Exited += (sender, args) => OnFfMpegProcessExited(process, transcodingJob, state);
             process.Exited += (sender, args) => OnFfMpegProcessExited(process, transcodingJob, state);
@@ -1105,6 +1086,10 @@ namespace MediaBrowser.Api.Playback
                     }
                     }
                 }
                 }
             }
             }
+            catch (ObjectDisposedException)
+            {
+                // Don't spam the log. This doesn't seem to throw in windows, but sometimes under linux
+            }
             catch (Exception ex)
             catch (Exception ex)
             {
             {
                 Logger.ErrorException("Error reading ffmpeg log", ex);
                 Logger.ErrorException("Error reading ffmpeg log", ex);
@@ -2033,8 +2018,6 @@ namespace MediaBrowser.Api.Playback
                 profile.GetVideoMediaProfile(state.OutputContainer,
                 profile.GetVideoMediaProfile(state.OutputContainer,
                 audioCodec,
                 audioCodec,
                 videoCodec,
                 videoCodec,
-                state.OutputAudioBitrate,
-                state.OutputAudioChannels,
                 state.OutputWidth,
                 state.OutputWidth,
                 state.OutputHeight,
                 state.OutputHeight,
                 state.TargetVideoBitDepth,
                 state.TargetVideoBitDepth,
@@ -2121,8 +2104,6 @@ namespace MediaBrowser.Api.Playback
                     state.OutputHeight,
                     state.OutputHeight,
                     state.TargetVideoBitDepth,
                     state.TargetVideoBitDepth,
                     state.OutputVideoBitrate,
                     state.OutputVideoBitrate,
-                    state.OutputAudioBitrate,
-                    state.OutputAudioChannels,
                     state.TargetTimestamp,
                     state.TargetTimestamp,
                     isStaticallyStreamed,
                     isStaticallyStreamed,
                     state.RunTimeTicks,
                     state.RunTimeTicks,

+ 2 - 1
MediaBrowser.Api/Playback/Dash/MpegDashService.cs

@@ -8,6 +8,7 @@ using MediaBrowser.Controller.Library;
 using MediaBrowser.Controller.MediaEncoding;
 using MediaBrowser.Controller.MediaEncoding;
 using MediaBrowser.Controller.Net;
 using MediaBrowser.Controller.Net;
 using MediaBrowser.Model.IO;
 using MediaBrowser.Model.IO;
+using MediaBrowser.Model.Serialization;
 using ServiceStack;
 using ServiceStack;
 using System;
 using System;
 using System.Collections.Generic;
 using System.Collections.Generic;
@@ -53,7 +54,7 @@ namespace MediaBrowser.Api.Playback.Dash
 
 
     public class MpegDashService : BaseHlsService
     public class MpegDashService : BaseHlsService
     {
     {
-        public MpegDashService(IServerConfigurationManager serverConfig, IUserManager userManager, ILibraryManager libraryManager, IIsoManager isoManager, IMediaEncoder mediaEncoder, IFileSystem fileSystem, IDlnaManager dlnaManager, ISubtitleEncoder subtitleEncoder, IDeviceManager deviceManager, IMediaSourceManager mediaSourceManager, IZipClient zipClient, INetworkManager networkManager) : base(serverConfig, userManager, libraryManager, isoManager, mediaEncoder, fileSystem, dlnaManager, subtitleEncoder, deviceManager, mediaSourceManager, zipClient)
+        public MpegDashService(IServerConfigurationManager serverConfig, IUserManager userManager, ILibraryManager libraryManager, IIsoManager isoManager, IMediaEncoder mediaEncoder, IFileSystem fileSystem, IDlnaManager dlnaManager, ISubtitleEncoder subtitleEncoder, IDeviceManager deviceManager, IMediaSourceManager mediaSourceManager, IZipClient zipClient, IJsonSerializer jsonSerializer, INetworkManager networkManager) : base(serverConfig, userManager, libraryManager, isoManager, mediaEncoder, fileSystem, dlnaManager, subtitleEncoder, deviceManager, mediaSourceManager, zipClient, jsonSerializer)
         {
         {
             NetworkManager = networkManager;
             NetworkManager = networkManager;
         }
         }

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

@@ -13,6 +13,7 @@ using System.IO;
 using System.Text;
 using System.Text;
 using System.Threading;
 using System.Threading;
 using System.Threading.Tasks;
 using System.Threading.Tasks;
+using MediaBrowser.Model.Serialization;
 
 
 namespace MediaBrowser.Api.Playback.Hls
 namespace MediaBrowser.Api.Playback.Hls
 {
 {
@@ -21,7 +22,7 @@ namespace MediaBrowser.Api.Playback.Hls
     /// </summary>
     /// </summary>
     public abstract class BaseHlsService : BaseStreamingService
     public abstract class BaseHlsService : BaseStreamingService
     {
     {
-        protected BaseHlsService(IServerConfigurationManager serverConfig, IUserManager userManager, ILibraryManager libraryManager, IIsoManager isoManager, IMediaEncoder mediaEncoder, IFileSystem fileSystem, IDlnaManager dlnaManager, ISubtitleEncoder subtitleEncoder, IDeviceManager deviceManager, IMediaSourceManager mediaSourceManager, IZipClient zipClient) : base(serverConfig, userManager, libraryManager, isoManager, mediaEncoder, fileSystem, dlnaManager, subtitleEncoder, deviceManager, mediaSourceManager, zipClient)
+        protected BaseHlsService(IServerConfigurationManager serverConfig, IUserManager userManager, ILibraryManager libraryManager, IIsoManager isoManager, IMediaEncoder mediaEncoder, IFileSystem fileSystem, IDlnaManager dlnaManager, ISubtitleEncoder subtitleEncoder, IDeviceManager deviceManager, IMediaSourceManager mediaSourceManager, IZipClient zipClient, IJsonSerializer jsonSerializer) : base(serverConfig, userManager, libraryManager, isoManager, mediaEncoder, fileSystem, dlnaManager, subtitleEncoder, deviceManager, mediaSourceManager, zipClient, jsonSerializer)
         {
         {
         }
         }
 
 

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

@@ -10,6 +10,7 @@ using MediaBrowser.Model.Dlna;
 using MediaBrowser.Model.Entities;
 using MediaBrowser.Model.Entities;
 using MediaBrowser.Model.Extensions;
 using MediaBrowser.Model.Extensions;
 using MediaBrowser.Model.IO;
 using MediaBrowser.Model.IO;
+using MediaBrowser.Model.Serialization;
 using ServiceStack;
 using ServiceStack;
 using System;
 using System;
 using System.Collections.Generic;
 using System.Collections.Generic;
@@ -61,7 +62,7 @@ namespace MediaBrowser.Api.Playback.Hls
 
 
     public class DynamicHlsService : BaseHlsService
     public class DynamicHlsService : BaseHlsService
     {
     {
-        public DynamicHlsService(IServerConfigurationManager serverConfig, IUserManager userManager, ILibraryManager libraryManager, IIsoManager isoManager, IMediaEncoder mediaEncoder, IFileSystem fileSystem, IDlnaManager dlnaManager, ISubtitleEncoder subtitleEncoder, IDeviceManager deviceManager, IMediaSourceManager mediaSourceManager, IZipClient zipClient, INetworkManager networkManager) : base(serverConfig, userManager, libraryManager, isoManager, mediaEncoder, fileSystem, dlnaManager, subtitleEncoder, deviceManager, mediaSourceManager, zipClient)
+        public DynamicHlsService(IServerConfigurationManager serverConfig, IUserManager userManager, ILibraryManager libraryManager, IIsoManager isoManager, IMediaEncoder mediaEncoder, IFileSystem fileSystem, IDlnaManager dlnaManager, ISubtitleEncoder subtitleEncoder, IDeviceManager deviceManager, IMediaSourceManager mediaSourceManager, IZipClient zipClient, IJsonSerializer jsonSerializer, INetworkManager networkManager) : base(serverConfig, userManager, libraryManager, isoManager, mediaEncoder, fileSystem, dlnaManager, subtitleEncoder, deviceManager, mediaSourceManager, zipClient, jsonSerializer)
         {
         {
             NetworkManager = networkManager;
             NetworkManager = networkManager;
         }
         }

+ 2 - 1
MediaBrowser.Api/Playback/Hls/VideoHlsService.cs

@@ -5,6 +5,7 @@ using MediaBrowser.Controller.Dlna;
 using MediaBrowser.Controller.Library;
 using MediaBrowser.Controller.Library;
 using MediaBrowser.Controller.MediaEncoding;
 using MediaBrowser.Controller.MediaEncoding;
 using MediaBrowser.Model.IO;
 using MediaBrowser.Model.IO;
+using MediaBrowser.Model.Serialization;
 using ServiceStack;
 using ServiceStack;
 using System;
 using System;
 
 
@@ -40,7 +41,7 @@ namespace MediaBrowser.Api.Playback.Hls
     /// </summary>
     /// </summary>
     public class VideoHlsService : BaseHlsService
     public class VideoHlsService : BaseHlsService
     {
     {
-        public VideoHlsService(IServerConfigurationManager serverConfig, IUserManager userManager, ILibraryManager libraryManager, IIsoManager isoManager, IMediaEncoder mediaEncoder, IFileSystem fileSystem, IDlnaManager dlnaManager, ISubtitleEncoder subtitleEncoder, IDeviceManager deviceManager, IMediaSourceManager mediaSourceManager, IZipClient zipClient) : base(serverConfig, userManager, libraryManager, isoManager, mediaEncoder, fileSystem, dlnaManager, subtitleEncoder, deviceManager, mediaSourceManager, zipClient)
+        public VideoHlsService(IServerConfigurationManager serverConfig, IUserManager userManager, ILibraryManager libraryManager, IIsoManager isoManager, IMediaEncoder mediaEncoder, IFileSystem fileSystem, IDlnaManager dlnaManager, ISubtitleEncoder subtitleEncoder, IDeviceManager deviceManager, IMediaSourceManager mediaSourceManager, IZipClient zipClient, IJsonSerializer jsonSerializer) : base(serverConfig, userManager, libraryManager, isoManager, mediaEncoder, fileSystem, dlnaManager, subtitleEncoder, deviceManager, mediaSourceManager, zipClient, jsonSerializer)
         {
         {
         }
         }
 
 

+ 23 - 14
MediaBrowser.Api/Playback/MediaInfoService.cs

@@ -18,16 +18,6 @@ using System.Threading.Tasks;
 
 
 namespace MediaBrowser.Api.Playback
 namespace MediaBrowser.Api.Playback
 {
 {
-    [Route("/Items/{Id}/MediaInfo", "GET", Summary = "Gets live playback media info for an item")]
-    public class GetLiveMediaInfo : IReturn<PlaybackInfoResponse>
-    {
-        [ApiMember(Name = "Id", Description = "Item Id", IsRequired = true, DataType = "string", ParameterType = "path", Verb = "GET")]
-        public string Id { get; set; }
-
-        [ApiMember(Name = "UserId", Description = "User Id", IsRequired = true, DataType = "string", ParameterType = "query", Verb = "GET")]
-        public string UserId { get; set; }
-    }
-
     [Route("/Items/{Id}/PlaybackInfo", "GET", Summary = "Gets live playback media info for an item")]
     [Route("/Items/{Id}/PlaybackInfo", "GET", Summary = "Gets live playback media info for an item")]
     public class GetPlaybackInfo : IReturn<PlaybackInfoResponse>
     public class GetPlaybackInfo : IReturn<PlaybackInfoResponse>
     {
     {
@@ -55,6 +45,19 @@ namespace MediaBrowser.Api.Playback
         public string LiveStreamId { get; set; }
         public string LiveStreamId { get; set; }
     }
     }
 
 
+    [Route("/Playback/BitrateTest", "GET")]
+    public class GetBitrateTestBytes : IReturn<PlaybackInfoResponse>
+    {
+        [ApiMember(Name = "Size", Description = "Size", IsRequired = true, DataType = "int", ParameterType = "query", Verb = "GET")]
+        public long Size { get; set; }
+
+        public GetBitrateTestBytes()
+        {
+            // 100k
+            Size = 102400;
+        }
+    }
+    
     [Authenticated]
     [Authenticated]
     public class MediaInfoService : BaseApiService
     public class MediaInfoService : BaseApiService
     {
     {
@@ -73,13 +76,19 @@ namespace MediaBrowser.Api.Playback
             _networkManager = networkManager;
             _networkManager = networkManager;
         }
         }
 
 
-        public async Task<object> Get(GetPlaybackInfo request)
+        public object Get(GetBitrateTestBytes request)
         {
         {
-            var result = await GetPlaybackInfo(request.Id, request.UserId, new[] { MediaType.Audio, MediaType.Video }).ConfigureAwait(false);
-            return ToOptimizedResult(result);
+            var bytes = new byte[request.Size];
+
+            for (var i = 0; i < bytes.Length; i++)
+            {
+                bytes[i] = 0;
+            }
+
+            return ResultFactory.GetResult(bytes, "application/octet-stream");
         }
         }
 
 
-        public async Task<object> Get(GetLiveMediaInfo request)
+        public async Task<object> Get(GetPlaybackInfo request)
         {
         {
             var result = await GetPlaybackInfo(request.Id, request.UserId, new[] { MediaType.Audio, MediaType.Video }).ConfigureAwait(false);
             var result = await GetPlaybackInfo(request.Id, request.UserId, new[] { MediaType.Audio, MediaType.Video }).ConfigureAwait(false);
             return ToOptimizedResult(result);
             return ToOptimizedResult(result);

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

@@ -8,6 +8,7 @@ using MediaBrowser.Controller.Library;
 using MediaBrowser.Controller.LiveTv;
 using MediaBrowser.Controller.LiveTv;
 using MediaBrowser.Controller.MediaEncoding;
 using MediaBrowser.Controller.MediaEncoding;
 using MediaBrowser.Model.IO;
 using MediaBrowser.Model.IO;
+using MediaBrowser.Model.Serialization;
 using ServiceStack;
 using ServiceStack;
 using System.Collections.Generic;
 using System.Collections.Generic;
 
 
@@ -31,7 +32,7 @@ namespace MediaBrowser.Api.Playback.Progressive
     /// </summary>
     /// </summary>
     public class AudioService : BaseProgressiveStreamingService
     public class AudioService : BaseProgressiveStreamingService
     {
     {
-        public AudioService(IServerConfigurationManager serverConfig, IUserManager userManager, ILibraryManager libraryManager, IIsoManager isoManager, IMediaEncoder mediaEncoder, IFileSystem fileSystem, IDlnaManager dlnaManager, ISubtitleEncoder subtitleEncoder, IDeviceManager deviceManager, IMediaSourceManager mediaSourceManager, IZipClient zipClient, IImageProcessor imageProcessor, IHttpClient httpClient) : base(serverConfig, userManager, libraryManager, isoManager, mediaEncoder, fileSystem, dlnaManager, subtitleEncoder, deviceManager, mediaSourceManager, zipClient, imageProcessor, httpClient)
+        public AudioService(IServerConfigurationManager serverConfig, IUserManager userManager, ILibraryManager libraryManager, IIsoManager isoManager, IMediaEncoder mediaEncoder, IFileSystem fileSystem, IDlnaManager dlnaManager, ISubtitleEncoder subtitleEncoder, IDeviceManager deviceManager, IMediaSourceManager mediaSourceManager, IZipClient zipClient, IJsonSerializer jsonSerializer, IImageProcessor imageProcessor, IHttpClient httpClient) : base(serverConfig, userManager, libraryManager, isoManager, mediaEncoder, fileSystem, dlnaManager, subtitleEncoder, deviceManager, mediaSourceManager, zipClient, jsonSerializer, imageProcessor, httpClient)
         {
         {
         }
         }
 
 

+ 2 - 1
MediaBrowser.Api/Playback/Progressive/BaseProgressiveStreamingService.cs

@@ -10,6 +10,7 @@ using MediaBrowser.Controller.MediaEncoding;
 using MediaBrowser.Controller.Net;
 using MediaBrowser.Controller.Net;
 using MediaBrowser.Model.IO;
 using MediaBrowser.Model.IO;
 using MediaBrowser.Model.MediaInfo;
 using MediaBrowser.Model.MediaInfo;
+using MediaBrowser.Model.Serialization;
 using ServiceStack.Web;
 using ServiceStack.Web;
 using System;
 using System;
 using System.Collections.Generic;
 using System.Collections.Generic;
@@ -27,7 +28,7 @@ namespace MediaBrowser.Api.Playback.Progressive
         protected readonly IImageProcessor ImageProcessor;
         protected readonly IImageProcessor ImageProcessor;
         protected readonly IHttpClient HttpClient;
         protected readonly IHttpClient HttpClient;
 
 
-        protected BaseProgressiveStreamingService(IServerConfigurationManager serverConfig, IUserManager userManager, ILibraryManager libraryManager, IIsoManager isoManager, IMediaEncoder mediaEncoder, IFileSystem fileSystem, IDlnaManager dlnaManager, ISubtitleEncoder subtitleEncoder, IDeviceManager deviceManager, IMediaSourceManager mediaSourceManager, IZipClient zipClient, IImageProcessor imageProcessor, IHttpClient httpClient) : base(serverConfig, userManager, libraryManager, isoManager, mediaEncoder, fileSystem, dlnaManager, subtitleEncoder, deviceManager, mediaSourceManager, zipClient)
+        protected BaseProgressiveStreamingService(IServerConfigurationManager serverConfig, IUserManager userManager, ILibraryManager libraryManager, IIsoManager isoManager, IMediaEncoder mediaEncoder, IFileSystem fileSystem, IDlnaManager dlnaManager, ISubtitleEncoder subtitleEncoder, IDeviceManager deviceManager, IMediaSourceManager mediaSourceManager, IZipClient zipClient, IJsonSerializer jsonSerializer, IImageProcessor imageProcessor, IHttpClient httpClient) : base(serverConfig, userManager, libraryManager, isoManager, mediaEncoder, fileSystem, dlnaManager, subtitleEncoder, deviceManager, mediaSourceManager, zipClient, jsonSerializer)
         {
         {
             ImageProcessor = imageProcessor;
             ImageProcessor = imageProcessor;
             HttpClient = httpClient;
             HttpClient = httpClient;

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

@@ -7,6 +7,7 @@ using MediaBrowser.Controller.Drawing;
 using MediaBrowser.Controller.Library;
 using MediaBrowser.Controller.Library;
 using MediaBrowser.Controller.MediaEncoding;
 using MediaBrowser.Controller.MediaEncoding;
 using MediaBrowser.Model.IO;
 using MediaBrowser.Model.IO;
+using MediaBrowser.Model.Serialization;
 using ServiceStack;
 using ServiceStack;
 using System;
 using System;
 using System.IO;
 using System.IO;
@@ -61,7 +62,7 @@ namespace MediaBrowser.Api.Playback.Progressive
     /// </summary>
     /// </summary>
     public class VideoService : BaseProgressiveStreamingService
     public class VideoService : BaseProgressiveStreamingService
     {
     {
-        public VideoService(IServerConfigurationManager serverConfig, IUserManager userManager, ILibraryManager libraryManager, IIsoManager isoManager, IMediaEncoder mediaEncoder, IFileSystem fileSystem, IDlnaManager dlnaManager, ISubtitleEncoder subtitleEncoder, IDeviceManager deviceManager, IMediaSourceManager mediaSourceManager, IZipClient zipClient, IImageProcessor imageProcessor, IHttpClient httpClient) : base(serverConfig, userManager, libraryManager, isoManager, mediaEncoder, fileSystem, dlnaManager, subtitleEncoder, deviceManager, mediaSourceManager, zipClient, imageProcessor, httpClient)
+        public VideoService(IServerConfigurationManager serverConfig, IUserManager userManager, ILibraryManager libraryManager, IIsoManager isoManager, IMediaEncoder mediaEncoder, IFileSystem fileSystem, IDlnaManager dlnaManager, ISubtitleEncoder subtitleEncoder, IDeviceManager deviceManager, IMediaSourceManager mediaSourceManager, IZipClient zipClient, IJsonSerializer jsonSerializer, IImageProcessor imageProcessor, IHttpClient httpClient) : base(serverConfig, userManager, libraryManager, isoManager, mediaEncoder, fileSystem, dlnaManager, subtitleEncoder, deviceManager, mediaSourceManager, zipClient, jsonSerializer, imageProcessor, httpClient)
         {
         {
         }
         }
 
 

+ 1 - 0
MediaBrowser.Api/Subtitles/SubtitleService.cs

@@ -100,6 +100,7 @@ namespace MediaBrowser.Api.Subtitles
     }
     }
 
 
     [Route("/Videos/{Id}/{MediaSourceId}/Subtitles/{Index}/subtitles.m3u8", "GET", Summary = "Gets an HLS subtitle playlist.")]
     [Route("/Videos/{Id}/{MediaSourceId}/Subtitles/{Index}/subtitles.m3u8", "GET", Summary = "Gets an HLS subtitle playlist.")]
+    [Authenticated]
     public class GetSubtitlePlaylist
     public class GetSubtitlePlaylist
     {
     {
         /// <summary>
         /// <summary>

+ 4 - 7
MediaBrowser.Common.Implementations/MediaBrowser.Common.Implementations.csproj

@@ -48,9 +48,9 @@
     <RunPostBuildEvent>Always</RunPostBuildEvent>
     <RunPostBuildEvent>Always</RunPostBuildEvent>
   </PropertyGroup>
   </PropertyGroup>
   <ItemGroup>
   <ItemGroup>
-    <Reference Include="NLog, Version=3.2.0.0, Culture=neutral, PublicKeyToken=5120e14c03d0593c, processorArchitecture=MSIL">
+    <Reference Include="NLog, Version=3.2.1.0, Culture=neutral, PublicKeyToken=5120e14c03d0593c, processorArchitecture=MSIL">
       <SpecificVersion>False</SpecificVersion>
       <SpecificVersion>False</SpecificVersion>
-      <HintPath>..\packages\NLog.3.2.0.0\lib\net45\NLog.dll</HintPath>
+      <HintPath>..\packages\NLog.3.2.1\lib\net45\NLog.dll</HintPath>
     </Reference>
     </Reference>
     <Reference Include="SharpCompress, Version=0.10.2.0, Culture=neutral, PublicKeyToken=beaf6f427e128133, processorArchitecture=MSIL">
     <Reference Include="SharpCompress, Version=0.10.2.0, Culture=neutral, PublicKeyToken=beaf6f427e128133, processorArchitecture=MSIL">
       <SpecificVersion>False</SpecificVersion>
       <SpecificVersion>False</SpecificVersion>
@@ -58,11 +58,8 @@
     </Reference>
     </Reference>
     <Reference Include="SimpleInjector, Version=2.7.0.0, Culture=neutral, PublicKeyToken=984cb50dea722e99, processorArchitecture=MSIL">
     <Reference Include="SimpleInjector, Version=2.7.0.0, Culture=neutral, PublicKeyToken=984cb50dea722e99, processorArchitecture=MSIL">
       <SpecificVersion>False</SpecificVersion>
       <SpecificVersion>False</SpecificVersion>
-      <HintPath>..\packages\SimpleInjector.2.7.0\lib\net45\SimpleInjector.dll</HintPath>
-    </Reference>
-    <Reference Include="SimpleInjector.Diagnostics, Version=2.7.0.0, Culture=neutral, PublicKeyToken=984cb50dea722e99, processorArchitecture=MSIL">
-      <SpecificVersion>False</SpecificVersion>
-      <HintPath>..\packages\SimpleInjector.2.7.0\lib\net45\SimpleInjector.Diagnostics.dll</HintPath>
+      <HintPath>..\packages\SimpleInjector.2.8.0\lib\net45\SimpleInjector.dll</HintPath>
+      <Private>True</Private>
     </Reference>
     </Reference>
     <Reference Include="System" />
     <Reference Include="System" />
     <Reference Include="System.Core" />
     <Reference Include="System.Core" />

+ 13 - 30
MediaBrowser.Common.Implementations/Networking/BaseNetworkManager.cs

@@ -6,16 +6,29 @@ using System.Linq;
 using System.Net;
 using System.Net;
 using System.Net.NetworkInformation;
 using System.Net.NetworkInformation;
 using System.Net.Sockets;
 using System.Net.Sockets;
+using System.Threading;
 
 
 namespace MediaBrowser.Common.Implementations.Networking
 namespace MediaBrowser.Common.Implementations.Networking
 {
 {
     public abstract class BaseNetworkManager
     public abstract class BaseNetworkManager
     {
     {
         protected ILogger Logger { get; private set; }
         protected ILogger Logger { get; private set; }
+        private Timer _clearCacheTimer;
 
 
         protected BaseNetworkManager(ILogger logger)
         protected BaseNetworkManager(ILogger logger)
         {
         {
             Logger = logger;
             Logger = logger;
+
+            // Can't use network change events due to a crash in Linux
+            _clearCacheTimer = new Timer(ClearCacheTimerCallback, null, TimeSpan.FromMinutes(1), TimeSpan.FromMinutes(1));
+        }
+
+        private void ClearCacheTimerCallback(object state)
+        {
+            lock (_localIpAddressSyncLock)
+            {
+                _localIpAddresses = null;
+            }
         }
         }
 
 
         private volatile List<string> _localIpAddresses;
         private volatile List<string> _localIpAddresses;
@@ -36,7 +49,6 @@ namespace MediaBrowser.Common.Implementations.Networking
                         var addresses = GetLocalIpAddressesInternal().ToList();
                         var addresses = GetLocalIpAddressesInternal().ToList();
 
 
                         _localIpAddresses = addresses;
                         _localIpAddresses = addresses;
-                        BindEvents();
 
 
                         return addresses;
                         return addresses;
                     }
                     }
@@ -46,35 +58,6 @@ namespace MediaBrowser.Common.Implementations.Networking
             return _localIpAddresses;
             return _localIpAddresses;
         }
         }
 
 
-        private void BindEvents()
-        {
-            NetworkChange.NetworkAddressChanged -= NetworkChange_NetworkAddressChanged;
-            NetworkChange.NetworkAvailabilityChanged -= NetworkChange_NetworkAvailabilityChanged;
-
-            NetworkChange.NetworkAddressChanged += NetworkChange_NetworkAddressChanged;
-            NetworkChange.NetworkAvailabilityChanged += NetworkChange_NetworkAvailabilityChanged;
-        }
-
-        void NetworkChange_NetworkAvailabilityChanged(object sender, NetworkAvailabilityEventArgs e)
-        {
-            Logger.Debug("NetworkAvailabilityChanged fired. Resetting cached network info.");
-
-            lock (_localIpAddressSyncLock)
-            {
-                _localIpAddresses = null;
-            }
-        }
-
-        void NetworkChange_NetworkAddressChanged(object sender, EventArgs e)
-        {
-            Logger.Debug("NetworkAddressChanged fired. Resetting cached network info.");
-
-            lock (_localIpAddressSyncLock)
-            {
-                _localIpAddresses = null;
-            }
-        }
-
         private IEnumerable<string> GetLocalIpAddressesInternal()
         private IEnumerable<string> GetLocalIpAddressesInternal()
         {
         {
             var list = GetIPsDefault()
             var list = GetIPsDefault()

+ 2 - 2
MediaBrowser.Common.Implementations/packages.config

@@ -1,5 +1,5 @@
 <?xml version="1.0" encoding="utf-8"?>
 <?xml version="1.0" encoding="utf-8"?>
 <packages>
 <packages>
-  <package id="NLog" version="3.2.0.0" targetFramework="net45" />
-  <package id="SimpleInjector" version="2.7.0" targetFramework="net45" />
+  <package id="NLog" version="3.2.1" targetFramework="net45" />
+  <package id="SimpleInjector" version="2.8.0" targetFramework="net45" />
 </packages>
 </packages>

+ 9 - 0
MediaBrowser.Controller/Dlna/ISsdpHandler.cs

@@ -0,0 +1,9 @@
+using System;
+
+namespace MediaBrowser.Controller.Dlna
+{
+    public interface ISsdpHandler
+    {
+        event EventHandler<SsdpMessageEventArgs> MessageReceived;
+    }
+}

+ 2 - 1
MediaBrowser.Dlna/Ssdp/SsdpMessageEventArgs.cs → MediaBrowser.Controller/Dlna/SsdpMessageEventArgs.cs

@@ -2,7 +2,7 @@
 using System.Collections.Generic;
 using System.Collections.Generic;
 using System.Net;
 using System.Net;
 
 
-namespace MediaBrowser.Dlna.Ssdp
+namespace MediaBrowser.Controller.Dlna
 {
 {
     public class SsdpMessageEventArgs
     public class SsdpMessageEventArgs
     {
     {
@@ -13,6 +13,7 @@ namespace MediaBrowser.Dlna.Ssdp
         public Dictionary<string, string> Headers { get; set; }
         public Dictionary<string, string> Headers { get; set; }
 
 
         public IPAddress LocalIp { get; set; }
         public IPAddress LocalIp { get; set; }
+        public byte[] Message { get; set; }
 
 
         public SsdpMessageEventArgs()
         public SsdpMessageEventArgs()
         {
         {

+ 8 - 30
MediaBrowser.Controller/Entities/Audio/Audio.cs

@@ -52,34 +52,6 @@ namespace MediaBrowser.Controller.Entities.Audio
         /// <value><c>true</c> if this instance has embedded image; otherwise, <c>false</c>.</value>
         /// <value><c>true</c> if this instance has embedded image; otherwise, <c>false</c>.</value>
         public bool HasEmbeddedImage { get; set; }
         public bool HasEmbeddedImage { get; set; }
 
 
-        /// <summary>
-        /// Override this to true if class should be grouped under a container in indicies
-        /// The container class should be defined via IndexContainer
-        /// </summary>
-        /// <value><c>true</c> if [group in index]; otherwise, <c>false</c>.</value>
-        [IgnoreDataMember]
-        public override bool GroupInIndex
-        {
-            get
-            {
-                return true;
-            }
-        }
-
-        /// <summary>
-        /// Override this to return the folder that should be used to construct a container
-        /// for this item in an index.  GroupInIndex should be true as well.
-        /// </summary>
-        /// <value>The index container.</value>
-        [IgnoreDataMember]
-        public override Folder IndexContainer
-        {
-            get
-            {
-                return LatestItemsIndexContainer ?? new MusicAlbum { Name = "Unknown Album" };
-            }
-        }
-
         [IgnoreDataMember]
         [IgnoreDataMember]
         protected override bool SupportsOwnedItems
         protected override bool SupportsOwnedItems
         {
         {
@@ -94,7 +66,7 @@ namespace MediaBrowser.Controller.Entities.Audio
         {
         {
             get
             get
             {
             {
-                return Parents.OfType<MusicAlbum>().FirstOrDefault();
+                return AlbumEntity;
             }
             }
         }
         }
 
 
@@ -148,6 +120,12 @@ namespace MediaBrowser.Controller.Entities.Audio
         /// <value>The album.</value>
         /// <value>The album.</value>
         public string Album { get; set; }
         public string Album { get; set; }
 
 
+        [IgnoreDataMember]
+        public MusicAlbum AlbumEntity
+        {
+            get { return FindParent<MusicAlbum>(); }
+        }
+
         /// <summary>
         /// <summary>
         /// Gets the type of the media.
         /// Gets the type of the media.
         /// </summary>
         /// </summary>
@@ -177,7 +155,7 @@ namespace MediaBrowser.Controller.Entities.Audio
         /// <returns>System.String.</returns>
         /// <returns>System.String.</returns>
         protected override string CreateUserDataKey()
         protected override string CreateUserDataKey()
         {
         {
-            var parent = FindParent<MusicAlbum>();
+            var parent = AlbumEntity;
 
 
             if (parent != null)
             if (parent != null)
             {
             {

+ 0 - 47
MediaBrowser.Controller/Entities/Audio/MusicAlbum.cs

@@ -2,7 +2,6 @@
 using MediaBrowser.Model.Configuration;
 using MediaBrowser.Model.Configuration;
 using MediaBrowser.Model.Entities;
 using MediaBrowser.Model.Entities;
 using MediaBrowser.Model.Users;
 using MediaBrowser.Model.Users;
-using System;
 using System.Collections.Generic;
 using System.Collections.Generic;
 using System.Linq;
 using System.Linq;
 using System.Runtime.Serialization;
 using System.Runtime.Serialization;
@@ -14,11 +13,8 @@ namespace MediaBrowser.Controller.Entities.Audio
     /// </summary>
     /// </summary>
     public class MusicAlbum : Folder, IHasAlbumArtist, IHasArtist, IHasMusicGenres, IHasLookupInfo<AlbumInfo>
     public class MusicAlbum : Folder, IHasAlbumArtist, IHasArtist, IHasMusicGenres, IHasLookupInfo<AlbumInfo>
     {
     {
-        public List<Guid> SoundtrackIds { get; set; }
-
         public MusicAlbum()
         public MusicAlbum()
         {
         {
-            SoundtrackIds = new List<Guid>();
             Artists = new List<string>();
             Artists = new List<string>();
             AlbumArtists = new List<string>();
             AlbumArtists = new List<string>();
         }
         }
@@ -77,49 +73,6 @@ namespace MediaBrowser.Controller.Entities.Audio
             return Tracks;
             return Tracks;
         }
         }
 
 
-        /// <summary>
-        /// Songs will group into us so don't also include us in the index
-        /// </summary>
-        /// <value><c>true</c> if [include in index]; otherwise, <c>false</c>.</value>
-        [IgnoreDataMember]
-        public override bool IncludeInIndex
-        {
-            get
-            {
-                return false;
-            }
-        }
-
-        /// <summary>
-        /// Override this to true if class should be grouped under a container in indicies
-        /// The container class should be defined via IndexContainer
-        /// </summary>
-        /// <value><c>true</c> if [group in index]; otherwise, <c>false</c>.</value>
-        [IgnoreDataMember]
-        public override bool GroupInIndex
-        {
-            get
-            {
-                return true;
-            }
-        }
-
-        /// <summary>
-        /// The unknwon artist
-        /// </summary>
-        private static readonly MusicArtist UnknwonArtist = new MusicArtist { Name = "<Unknown>" };
-
-        /// <summary>
-        /// Override this to return the folder that should be used to construct a container
-        /// for this item in an index.  GroupInIndex should be true as well.
-        /// </summary>
-        /// <value>The index container.</value>
-        [IgnoreDataMember]
-        public override Folder IndexContainer
-        {
-            get { return Parent as MusicArtist ?? UnknwonArtist; }
-        }
-
         public List<string> Artists { get; set; }
         public List<string> Artists { get; set; }
 
 
         /// <summary>
         /// <summary>

+ 0 - 32
MediaBrowser.Controller/Entities/BaseItem.cs

@@ -906,38 +906,6 @@ namespace MediaBrowser.Controller.Entities
         /// <value>The provider ids.</value>
         /// <value>The provider ids.</value>
         public Dictionary<string, string> ProviderIds { get; set; }
         public Dictionary<string, string> ProviderIds { get; set; }
 
 
-        /// <summary>
-        /// Override this to false if class should be ignored for indexing purposes
-        /// </summary>
-        /// <value><c>true</c> if [include in index]; otherwise, <c>false</c>.</value>
-        [IgnoreDataMember]
-        public virtual bool IncludeInIndex
-        {
-            get { return true; }
-        }
-
-        /// <summary>
-        /// Override this to true if class should be grouped under a container in indicies
-        /// The container class should be defined via IndexContainer
-        /// </summary>
-        /// <value><c>true</c> if [group in index]; otherwise, <c>false</c>.</value>
-        [IgnoreDataMember]
-        public virtual bool GroupInIndex
-        {
-            get { return false; }
-        }
-
-        /// <summary>
-        /// Override this to return the folder that should be used to construct a container
-        /// for this item in an index.  GroupInIndex should be true as well.
-        /// </summary>
-        /// <value>The index container.</value>
-        [IgnoreDataMember]
-        public virtual Folder IndexContainer
-        {
-            get { return null; }
-        }
-
         [IgnoreDataMember]
         [IgnoreDataMember]
         public virtual Folder LatestItemsIndexContainer
         public virtual Folder LatestItemsIndexContainer
         {
         {

+ 0 - 23
MediaBrowser.Controller/Entities/TV/Episode.cs

@@ -45,16 +45,6 @@ namespace MediaBrowser.Controller.Entities.TV
         /// <value>The index number.</value>
         /// <value>The index number.</value>
         public int? IndexNumberEnd { get; set; }
         public int? IndexNumberEnd { get; set; }
 
 
-        /// <summary>
-        /// We want to group into series not show individually in an index
-        /// </summary>
-        /// <value><c>true</c> if [group in index]; otherwise, <c>false</c>.</value>
-        [IgnoreDataMember]
-        public override bool GroupInIndex
-        {
-            get { return true; }
-        }
-
         [IgnoreDataMember]
         [IgnoreDataMember]
         protected override bool SupportsOwnedItems
         protected override bool SupportsOwnedItems
         {
         {
@@ -91,19 +81,6 @@ namespace MediaBrowser.Controller.Entities.TV
             }
             }
         }
         }
 
 
-        /// <summary>
-        /// We roll up into series
-        /// </summary>
-        /// <value>The index container.</value>
-        [IgnoreDataMember]
-        public override Folder IndexContainer
-        {
-            get
-            {
-                return Season;
-            }
-        }
-
         [IgnoreDataMember]
         [IgnoreDataMember]
         public override Folder LatestItemsIndexContainer
         public override Folder LatestItemsIndexContainer
         {
         {

+ 1 - 43
MediaBrowser.Controller/Entities/TV/Season.cs

@@ -1,5 +1,4 @@
-using MediaBrowser.Controller.Localization;
-using MediaBrowser.Controller.Providers;
+using MediaBrowser.Controller.Providers;
 using MediaBrowser.Model.Entities;
 using MediaBrowser.Model.Entities;
 using MediaBrowser.Model.Querying;
 using MediaBrowser.Model.Querying;
 using MediaBrowser.Model.Users;
 using MediaBrowser.Model.Users;
@@ -15,20 +14,6 @@ namespace MediaBrowser.Controller.Entities.TV
     /// </summary>
     /// </summary>
     public class Season : Folder, IHasSeries, IHasLookupInfo<SeasonInfo>
     public class Season : Folder, IHasSeries, IHasLookupInfo<SeasonInfo>
     {
     {
-
-        /// <summary>
-        /// Seasons are just containers
-        /// </summary>
-        /// <value><c>true</c> if [include in index]; otherwise, <c>false</c>.</value>
-        [IgnoreDataMember]
-        public override bool IncludeInIndex
-        {
-            get
-            {
-                return false;
-            }
-        }
-
         [IgnoreDataMember]
         [IgnoreDataMember]
         public override bool SupportsAddingToPlaylist
         public override bool SupportsAddingToPlaylist
         {
         {
@@ -50,33 +35,6 @@ namespace MediaBrowser.Controller.Entities.TV
             get { return Series ?? Parent; }
             get { return Series ?? Parent; }
         }
         }
 
 
-        /// <summary>
-        /// We want to group into our Series
-        /// </summary>
-        /// <value><c>true</c> if [group in index]; otherwise, <c>false</c>.</value>
-        [IgnoreDataMember]
-        public override bool GroupInIndex
-        {
-            get
-            {
-                return true;
-            }
-        }
-
-        /// <summary>
-        /// Override this to return the folder that should be used to construct a container
-        /// for this item in an index.  GroupInIndex should be true as well.
-        /// </summary>
-        /// <value>The index container.</value>
-        [IgnoreDataMember]
-        public override Folder IndexContainer
-        {
-            get
-            {
-                return Series;
-            }
-        }
-
         // Genre, Rating and Stuido will all be the same
         // Genre, Rating and Stuido will all be the same
         protected override IEnumerable<string> GetIndexByOptions()
         protected override IEnumerable<string> GetIndexByOptions()
         {
         {

+ 0 - 13
MediaBrowser.Controller/Entities/TV/Series.cs

@@ -94,19 +94,6 @@ namespace MediaBrowser.Controller.Entities.TV
             }
             }
         }
         }
 
 
-        /// <summary>
-        /// Series aren't included directly in indices - Their Episodes will roll up to them
-        /// </summary>
-        /// <value><c>true</c> if [include in index]; otherwise, <c>false</c>.</value>
-        [IgnoreDataMember]
-        public override bool IncludeInIndex
-        {
-            get
-            {
-                return false;
-            }
-        }
-
         /// <summary>
         /// <summary>
         /// Gets the user data key.
         /// Gets the user data key.
         /// </summary>
         /// </summary>

+ 12 - 0
MediaBrowser.Controller/Entities/User.cs

@@ -283,5 +283,17 @@ namespace MediaBrowser.Controller.Entities
 
 
             return hour >= schedule.StartHour && hour <= schedule.EndHour;
             return hour >= schedule.StartHour && hour <= schedule.EndHour;
         }
         }
+
+        public bool IsFolderGrouped(Guid id)
+        {
+            var config = Configuration;
+
+            if (config.ExcludeFoldersFromGrouping != null)
+            {
+                return !config.ExcludeFoldersFromGrouping.Select(i => new Guid(i)).Contains(id);
+            }
+
+            return config.GroupedFolders.Select(i => new Guid(i)).Contains(id);
+        }
     }
     }
 }
 }

+ 1 - 3
MediaBrowser.Controller/Entities/UserViewBuilder.cs

@@ -1754,12 +1754,10 @@ namespace MediaBrowser.Controller.Entities
 
 
         private IEnumerable<Folder> GetMediaFolders(User user)
         private IEnumerable<Folder> GetMediaFolders(User user)
         {
         {
-            var excludeFolderIds = user.Configuration.ExcludeFoldersFromGrouping.Select(i => new Guid(i)).ToList();
-
             return user.RootFolder
             return user.RootFolder
                 .GetChildren(user, true, true)
                 .GetChildren(user, true, true)
                 .OfType<Folder>()
                 .OfType<Folder>()
-                .Where(i => !excludeFolderIds.Contains(i.Id) && !UserView.IsExcludedFromGrouping(i));
+                .Where(i => user.IsFolderGrouped(i.Id) && !UserView.IsExcludedFromGrouping(i));
         }
         }
 
 
         private IEnumerable<Folder> GetMediaFolders(User user, IEnumerable<string> viewTypes)
         private IEnumerable<Folder> GetMediaFolders(User user, IEnumerable<string> viewTypes)

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

@@ -116,7 +116,9 @@
     <Compile Include="Dlna\IDlnaManager.cs" />
     <Compile Include="Dlna\IDlnaManager.cs" />
     <Compile Include="Dlna\IEventManager.cs" />
     <Compile Include="Dlna\IEventManager.cs" />
     <Compile Include="Dlna\IMediaReceiverRegistrar.cs" />
     <Compile Include="Dlna\IMediaReceiverRegistrar.cs" />
+    <Compile Include="Dlna\ISsdpHandler.cs" />
     <Compile Include="Dlna\IUpnpService.cs" />
     <Compile Include="Dlna\IUpnpService.cs" />
+    <Compile Include="Dlna\SsdpMessageEventArgs.cs" />
     <Compile Include="Drawing\IImageProcessor.cs" />
     <Compile Include="Drawing\IImageProcessor.cs" />
     <Compile Include="Drawing\ImageCollageOptions.cs" />
     <Compile Include="Drawing\ImageCollageOptions.cs" />
     <Compile Include="Drawing\ImageProcessingOptions.cs" />
     <Compile Include="Drawing\ImageProcessingOptions.cs" />

+ 1 - 0
MediaBrowser.Dlna/Channels/DlnaChannelFactory.cs

@@ -2,6 +2,7 @@
 using MediaBrowser.Common.Net;
 using MediaBrowser.Common.Net;
 using MediaBrowser.Controller.Channels;
 using MediaBrowser.Controller.Channels;
 using MediaBrowser.Controller.Configuration;
 using MediaBrowser.Controller.Configuration;
+using MediaBrowser.Controller.Dlna;
 using MediaBrowser.Controller.Providers;
 using MediaBrowser.Controller.Providers;
 using MediaBrowser.Dlna.ContentDirectory;
 using MediaBrowser.Dlna.ContentDirectory;
 using MediaBrowser.Dlna.PlayTo;
 using MediaBrowser.Dlna.PlayTo;

+ 0 - 4
MediaBrowser.Dlna/Didl/DidlBuilder.cs

@@ -149,8 +149,6 @@ namespace MediaBrowser.Dlna.Didl
                 targetHeight,
                 targetHeight,
                 streamInfo.TargetVideoBitDepth,
                 streamInfo.TargetVideoBitDepth,
                 streamInfo.TargetVideoBitrate,
                 streamInfo.TargetVideoBitrate,
-                streamInfo.TargetAudioChannels,
-                streamInfo.TargetAudioBitrate,
                 streamInfo.TargetTimestamp,
                 streamInfo.TargetTimestamp,
                 streamInfo.IsDirectStream,
                 streamInfo.IsDirectStream,
                 streamInfo.RunTimeTicks,
                 streamInfo.RunTimeTicks,
@@ -276,11 +274,9 @@ namespace MediaBrowser.Dlna.Didl
                 streamInfo.AudioCodec,
                 streamInfo.AudioCodec,
                 streamInfo.VideoCodec,
                 streamInfo.VideoCodec,
                 streamInfo.TargetAudioBitrate,
                 streamInfo.TargetAudioBitrate,
-                targetChannels,
                 targetWidth,
                 targetWidth,
                 targetHeight,
                 targetHeight,
                 streamInfo.TargetVideoBitDepth,
                 streamInfo.TargetVideoBitDepth,
-                streamInfo.TargetVideoBitrate,
                 streamInfo.TargetVideoProfile,
                 streamInfo.TargetVideoProfile,
                 streamInfo.TargetVideoLevel,
                 streamInfo.TargetVideoLevel,
                 streamInfo.TargetFramerate,
                 streamInfo.TargetFramerate,

+ 4 - 2
MediaBrowser.Dlna/DlnaManager.cs

@@ -482,7 +482,7 @@ namespace MediaBrowser.Dlna
             var profile = GetProfile(headers) ??
             var profile = GetProfile(headers) ??
                           GetDefaultProfile();
                           GetDefaultProfile();
 
 
-            return new DescriptionXmlBuilder(profile, serverUuId, serverAddress, _appHost.FriendlyName).GetXml();
+            return new DescriptionXmlBuilder(profile, serverUuId, serverAddress, _appHost.FriendlyName, serverUuId.GetMD5().ToString("N")).GetXml();
         }
         }
 
 
         public ImageStream GetIcon(string filename)
         public ImageStream GetIcon(string filename)
@@ -544,7 +544,9 @@ namespace MediaBrowser.Dlna
                 new DirectTvProfile(),
                 new DirectTvProfile(),
                 new DishHopperJoeyProfile(),
                 new DishHopperJoeyProfile(),
                 new DefaultProfile(),
                 new DefaultProfile(),
-                new PopcornHourProfile()
+                new PopcornHourProfile(),
+                new VlcProfile(),
+                new BubbleUpnpProfile()
             };
             };
 
 
             foreach (var item in list)
             foreach (var item in list)

+ 18 - 38
MediaBrowser.Dlna/Main/DlnaEntryPoint.cs

@@ -37,13 +37,26 @@ namespace MediaBrowser.Dlna.Main
         private readonly ILocalizationManager _localization;
         private readonly ILocalizationManager _localization;
         private readonly IMediaSourceManager _mediaSourceManager;
         private readonly IMediaSourceManager _mediaSourceManager;
 
 
-        private SsdpHandler _ssdpHandler;
+        private readonly SsdpHandler _ssdpHandler;
         private DeviceDiscovery _deviceDiscovery;
         private DeviceDiscovery _deviceDiscovery;
 
 
         private readonly List<string> _registeredServerIds = new List<string>();
         private readonly List<string> _registeredServerIds = new List<string>();
         private bool _dlnaServerStarted;
         private bool _dlnaServerStarted;
 
 
-        public DlnaEntryPoint(IServerConfigurationManager config, ILogManager logManager, IServerApplicationHost appHost, INetworkManager network, ISessionManager sessionManager, IHttpClient httpClient, ILibraryManager libraryManager, IUserManager userManager, IDlnaManager dlnaManager, IImageProcessor imageProcessor, IUserDataManager userDataManager, ILocalizationManager localization, IMediaSourceManager mediaSourceManager)
+        public DlnaEntryPoint(IServerConfigurationManager config, 
+            ILogManager logManager, 
+            IServerApplicationHost appHost, 
+            INetworkManager network, 
+            ISessionManager sessionManager, 
+            IHttpClient httpClient, 
+            ILibraryManager libraryManager, 
+            IUserManager userManager, 
+            IDlnaManager dlnaManager, 
+            IImageProcessor imageProcessor, 
+            IUserDataManager userDataManager, 
+            ILocalizationManager localization, 
+            IMediaSourceManager mediaSourceManager, 
+            ISsdpHandler ssdpHandler)
         {
         {
             _config = config;
             _config = config;
             _appHost = appHost;
             _appHost = appHost;
@@ -57,6 +70,7 @@ namespace MediaBrowser.Dlna.Main
             _userDataManager = userDataManager;
             _userDataManager = userDataManager;
             _localization = localization;
             _localization = localization;
             _mediaSourceManager = mediaSourceManager;
             _mediaSourceManager = mediaSourceManager;
+            _ssdpHandler = (SsdpHandler)ssdpHandler;
             _logger = logManager.GetLogger("Dlna");
             _logger = logManager.GetLogger("Dlna");
         }
         }
 
 
@@ -109,8 +123,6 @@ namespace MediaBrowser.Dlna.Main
         {
         {
             try
             try
             {
             {
-                _ssdpHandler = new SsdpHandler(_logger, _config, GenerateServerSignature());
-
                 _ssdpHandler.Start();
                 _ssdpHandler.Start();
 
 
                 _deviceDiscovery = new DeviceDiscovery(_logger, _config, _ssdpHandler, _appHost);
                 _deviceDiscovery = new DeviceDiscovery(_logger, _config, _ssdpHandler, _appHost);
@@ -123,7 +135,7 @@ namespace MediaBrowser.Dlna.Main
             }
             }
         }
         }
 
 
-        private void DisposeSsdpHandler()
+        private void DisposeDeviceDiscovery()
         {
         {
             try
             try
             {
             {
@@ -133,15 +145,6 @@ namespace MediaBrowser.Dlna.Main
             {
             {
                 _logger.ErrorException("Error disposing device discovery", ex);
                 _logger.ErrorException("Error disposing device discovery", ex);
             }
             }
-
-            try
-            {
-                _ssdpHandler.Dispose();
-            }
-            catch (Exception ex)
-            {
-                _logger.ErrorException("Error disposing ssdp handler", ex);
-            }
         }
         }
 
 
         public void StartDlnaServer()
         public void StartDlnaServer()
@@ -184,29 +187,6 @@ namespace MediaBrowser.Dlna.Main
             }
             }
         }
         }
 
 
-        private string GenerateServerSignature()
-        {
-            var os = Environment.OSVersion;
-            var pstring = os.Platform.ToString();
-            switch (os.Platform)
-            {
-                case PlatformID.Win32NT:
-                case PlatformID.Win32S:
-                case PlatformID.Win32Windows:
-                    pstring = "WIN";
-                    break;
-            }
-
-            return String.Format(
-              "{0}{1}/{2}.{3} UPnP/1.0 DLNADOC/1.5 MediaBrowser/{4}",
-              pstring,
-              IntPtr.Size * 8,
-              os.Version.Major,
-              os.Version.Minor,
-              _appHost.ApplicationVersion
-              );
-        }
-
         private readonly object _syncLock = new object();
         private readonly object _syncLock = new object();
         private void StartPlayToManager()
         private void StartPlayToManager()
         {
         {
@@ -260,7 +240,7 @@ namespace MediaBrowser.Dlna.Main
         {
         {
             DisposeDlnaServer();
             DisposeDlnaServer();
             DisposePlayToManager();
             DisposePlayToManager();
-            DisposeSsdpHandler();
+            DisposeDeviceDiscovery();
         }
         }
 
 
         public void DisposeDlnaServer()
         public void DisposeDlnaServer()

+ 6 - 1
MediaBrowser.Dlna/MediaBrowser.Dlna.csproj

@@ -77,10 +77,12 @@
     <Compile Include="Common\DeviceService.cs" />
     <Compile Include="Common\DeviceService.cs" />
     <Compile Include="Didl\DidlBuilder.cs" />
     <Compile Include="Didl\DidlBuilder.cs" />
     <Compile Include="PlayTo\PlayToController.cs" />
     <Compile Include="PlayTo\PlayToController.cs" />
+    <Compile Include="Profiles\BubbleUpnpProfile.cs" />
     <Compile Include="Profiles\DefaultProfile.cs" />
     <Compile Include="Profiles\DefaultProfile.cs" />
     <Compile Include="Profiles\DirectTvProfile.cs" />
     <Compile Include="Profiles\DirectTvProfile.cs" />
     <Compile Include="Profiles\DishHopperJoeyProfile.cs" />
     <Compile Include="Profiles\DishHopperJoeyProfile.cs" />
     <Compile Include="Profiles\PopcornHourProfile.cs" />
     <Compile Include="Profiles\PopcornHourProfile.cs" />
+    <Compile Include="Profiles\VlcProfile.cs" />
     <Compile Include="Ssdp\DeviceDiscoveryInfo.cs" />
     <Compile Include="Ssdp\DeviceDiscoveryInfo.cs" />
     <Compile Include="Ssdp\Extensions.cs" />
     <Compile Include="Ssdp\Extensions.cs" />
     <Compile Include="PlayTo\PlaybackProgressEventArgs.cs" />
     <Compile Include="PlayTo\PlaybackProgressEventArgs.cs" />
@@ -135,7 +137,6 @@
     <Compile Include="Server\Headers.cs" />
     <Compile Include="Server\Headers.cs" />
     <Compile Include="Server\UpnpDevice.cs" />
     <Compile Include="Server\UpnpDevice.cs" />
     <Compile Include="Ssdp\SsdpMessageBuilder.cs" />
     <Compile Include="Ssdp\SsdpMessageBuilder.cs" />
-    <Compile Include="Ssdp\SsdpMessageEventArgs.cs" />
     <Compile Include="Ssdp\SsdpHandler.cs" />
     <Compile Include="Ssdp\SsdpHandler.cs" />
   </ItemGroup>
   </ItemGroup>
   <ItemGroup>
   <ItemGroup>
@@ -205,6 +206,10 @@
     <EmbeddedResource Include="Images\people480.jpg" />
     <EmbeddedResource Include="Images\people480.jpg" />
     <EmbeddedResource Include="Images\people480.png" />
     <EmbeddedResource Include="Images\people480.png" />
   </ItemGroup>
   </ItemGroup>
+  <ItemGroup>
+    <EmbeddedResource Include="Profiles\Xml\BubbleUPnp.xml" />
+    <EmbeddedResource Include="Profiles\Xml\Vlc.xml" />
+  </ItemGroup>
   <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
   <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
   <!-- To modify your build process, add your task inside one of the targets below and uncomment it. 
   <!-- To modify your build process, add your task inside one of the targets below and uncomment it. 
        Other similar extension points exist, see Microsoft.Common.targets.
        Other similar extension points exist, see Microsoft.Common.targets.

+ 8 - 8
MediaBrowser.Dlna/PlayTo/Device.cs

@@ -296,7 +296,7 @@ namespace MediaBrowser.Dlna.PlayTo
             }
             }
 
 
             var post = AvCommands.BuildPost(command, service.ServiceType, url, dictionary);
             var post = AvCommands.BuildPost(command, service.ServiceType, url, dictionary);
-            await new SsdpHttpClient(_httpClient, _config).SendCommandAsync(Properties.BaseUrl, service, command.Name, post, header)
+            await new SsdpHttpClient(_httpClient, _config).SendCommandAsync(Properties.BaseUrl, service, command.Name, post, header: header)
                 .ConfigureAwait(false);
                 .ConfigureAwait(false);
 
 
             await Task.Delay(50).ConfigureAwait(false);
             await Task.Delay(50).ConfigureAwait(false);
@@ -463,10 +463,10 @@ namespace MediaBrowser.Dlna.PlayTo
 
 
             if (service == null)
             if (service == null)
             {
             {
-                throw new InvalidOperationException("Unable to find service");
+                return;
             }
             }
 
 
-            var result = await new SsdpHttpClient(_httpClient, _config).SendCommandAsync(Properties.BaseUrl, service, command.Name, RendererCommands.BuildPost(command, service.ServiceType))
+            var result = await new SsdpHttpClient(_httpClient, _config).SendCommandAsync(Properties.BaseUrl, service, command.Name, RendererCommands.BuildPost(command, service.ServiceType), true)
                 .ConfigureAwait(false);
                 .ConfigureAwait(false);
 
 
             if (result == null || result.Document == null)
             if (result == null || result.Document == null)
@@ -496,10 +496,10 @@ namespace MediaBrowser.Dlna.PlayTo
 
 
             if (service == null)
             if (service == null)
             {
             {
-                throw new InvalidOperationException("Unable to find service");
+                return;
             }
             }
 
 
-            var result = await new SsdpHttpClient(_httpClient, _config).SendCommandAsync(Properties.BaseUrl, service, command.Name, RendererCommands.BuildPost(command, service.ServiceType))
+            var result = await new SsdpHttpClient(_httpClient, _config).SendCommandAsync(Properties.BaseUrl, service, command.Name, RendererCommands.BuildPost(command, service.ServiceType), true)
                 .ConfigureAwait(false);
                 .ConfigureAwait(false);
 
 
             if (result == null || result.Document == null)
             if (result == null || result.Document == null)
@@ -521,7 +521,7 @@ namespace MediaBrowser.Dlna.PlayTo
             if (service == null)
             if (service == null)
                 return null;
                 return null;
 
 
-            var result = await new SsdpHttpClient(_httpClient, _config).SendCommandAsync(Properties.BaseUrl, service, command.Name, AvCommands.BuildPost(command, service.ServiceType))
+            var result = await new SsdpHttpClient(_httpClient, _config).SendCommandAsync(Properties.BaseUrl, service, command.Name, AvCommands.BuildPost(command, service.ServiceType), false)
                 .ConfigureAwait(false);
                 .ConfigureAwait(false);
 
 
             if (result == null || result.Document == null)
             if (result == null || result.Document == null)
@@ -558,7 +558,7 @@ namespace MediaBrowser.Dlna.PlayTo
                 throw new InvalidOperationException("Unable to find service");
                 throw new InvalidOperationException("Unable to find service");
             }
             }
 
 
-            var result = await new SsdpHttpClient(_httpClient, _config).SendCommandAsync(Properties.BaseUrl, service, command.Name, RendererCommands.BuildPost(command, service.ServiceType))
+            var result = await new SsdpHttpClient(_httpClient, _config).SendCommandAsync(Properties.BaseUrl, service, command.Name, RendererCommands.BuildPost(command, service.ServiceType), false)
                 .ConfigureAwait(false);
                 .ConfigureAwait(false);
 
 
             if (result == null || result.Document == null)
             if (result == null || result.Document == null)
@@ -589,7 +589,7 @@ namespace MediaBrowser.Dlna.PlayTo
                 throw new InvalidOperationException("Unable to find service");
                 throw new InvalidOperationException("Unable to find service");
             }
             }
 
 
-            var result = await new SsdpHttpClient(_httpClient, _config).SendCommandAsync(Properties.BaseUrl, service, command.Name, RendererCommands.BuildPost(command, service.ServiceType))
+            var result = await new SsdpHttpClient(_httpClient, _config).SendCommandAsync(Properties.BaseUrl, service, command.Name, RendererCommands.BuildPost(command, service.ServiceType), false)
                 .ConfigureAwait(false);
                 .ConfigureAwait(false);
 
 
             if (result == null || result.Document == null)
             if (result == null || result.Document == null)

+ 4 - 3
MediaBrowser.Dlna/PlayTo/PlayToController.cs

@@ -509,8 +509,6 @@ namespace MediaBrowser.Dlna.PlayTo
                     streamInfo.TargetHeight,
                     streamInfo.TargetHeight,
                     streamInfo.TargetVideoBitDepth,
                     streamInfo.TargetVideoBitDepth,
                     streamInfo.TargetVideoBitrate,
                     streamInfo.TargetVideoBitrate,
-                    streamInfo.TargetAudioChannels,
-                    streamInfo.TargetAudioBitrate,
                     streamInfo.TargetTimestamp,
                     streamInfo.TargetTimestamp,
                     streamInfo.IsDirectStream,
                     streamInfo.IsDirectStream,
                     streamInfo.RunTimeTicks,
                     streamInfo.RunTimeTicks,
@@ -770,8 +768,11 @@ namespace MediaBrowser.Dlna.PlayTo
 
 
                     await _device.SetAvTransport(newItem.StreamUrl, GetDlnaHeaders(newItem), newItem.Didl).ConfigureAwait(false);
                     await _device.SetAvTransport(newItem.StreamUrl, GetDlnaHeaders(newItem), newItem.Didl).ConfigureAwait(false);
 
 
-                    if (newItem.StreamInfo.IsDirectStream)
+                    if (newItem.StreamInfo.IsDirectStream && newPosition > 0)
                     {
                     {
+                        // This is rather arbitrary, but give the player time to start playing
+                        await Task.Delay(2000).ConfigureAwait(false);
+
                         await _device.Seek(TimeSpan.FromTicks(newPosition)).ConfigureAwait(false);
                         await _device.Seek(TimeSpan.FromTicks(newPosition)).ConfigureAwait(false);
                     }
                     }
                 }
                 }

+ 82 - 49
MediaBrowser.Dlna/PlayTo/PlayToManager.cs

@@ -13,6 +13,7 @@ using System;
 using System.Collections.Generic;
 using System.Collections.Generic;
 using System.Linq;
 using System.Linq;
 using System.Net;
 using System.Net;
+using System.Threading;
 
 
 namespace MediaBrowser.Dlna.PlayTo
 namespace MediaBrowser.Dlna.PlayTo
 {
 {
@@ -34,6 +35,9 @@ namespace MediaBrowser.Dlna.PlayTo
         private readonly DeviceDiscovery _deviceDiscovery;
         private readonly DeviceDiscovery _deviceDiscovery;
         private readonly IMediaSourceManager _mediaSourceManager;
         private readonly IMediaSourceManager _mediaSourceManager;
 
 
+        private readonly List<string> _nonRendererUrls = new List<string>();
+        private Timer _clearNonRenderersTimer;
+
         public PlayToManager(ILogger logger, ISessionManager sessionManager, ILibraryManager libraryManager, IUserManager userManager, IDlnaManager dlnaManager, IServerApplicationHost appHost, IImageProcessor imageProcessor, DeviceDiscovery deviceDiscovery, IHttpClient httpClient, IServerConfigurationManager config, IUserDataManager userDataManager, ILocalizationManager localization, IMediaSourceManager mediaSourceManager)
         public PlayToManager(ILogger logger, ISessionManager sessionManager, ILibraryManager libraryManager, IUserManager userManager, IDlnaManager dlnaManager, IServerApplicationHost appHost, IImageProcessor imageProcessor, DeviceDiscovery deviceDiscovery, IHttpClient httpClient, IServerConfigurationManager config, IUserDataManager userDataManager, ILocalizationManager localization, IMediaSourceManager mediaSourceManager)
         {
         {
             _logger = logger;
             _logger = logger;
@@ -53,9 +57,19 @@ namespace MediaBrowser.Dlna.PlayTo
 
 
         public void Start()
         public void Start()
         {
         {
+            _clearNonRenderersTimer = new Timer(OnClearUrlTimerCallback, null, TimeSpan.FromMinutes(10), TimeSpan.FromMinutes(10));
+
             _deviceDiscovery.DeviceDiscovered += _deviceDiscovery_DeviceDiscovered;
             _deviceDiscovery.DeviceDiscovered += _deviceDiscovery_DeviceDiscovered;
         }
         }
 
 
+        private void OnClearUrlTimerCallback(object state)
+        {
+            lock (_nonRendererUrls)
+            {
+                _nonRendererUrls.Clear();
+            }
+        }
+
         async void _deviceDiscovery_DeviceDiscovered(object sender, SsdpMessageEventArgs e)
         async void _deviceDiscovery_DeviceDiscovered(object sender, SsdpMessageEventArgs e)
         {
         {
             var localIp = e.LocalIp;
             var localIp = e.LocalIp;
@@ -68,7 +82,7 @@ namespace MediaBrowser.Dlna.PlayTo
 
 
             string location;
             string location;
             if (!e.Headers.TryGetValue("Location", out location)) location = string.Empty;
             if (!e.Headers.TryGetValue("Location", out location)) location = string.Empty;
-            
+
             // It has to report that it's a media renderer
             // It has to report that it's a media renderer
             if (usn.IndexOf("MediaRenderer:", StringComparison.OrdinalIgnoreCase) == -1 &&
             if (usn.IndexOf("MediaRenderer:", StringComparison.OrdinalIgnoreCase) == -1 &&
                      nt.IndexOf("MediaRenderer:", StringComparison.OrdinalIgnoreCase) == -1)
                      nt.IndexOf("MediaRenderer:", StringComparison.OrdinalIgnoreCase) == -1)
@@ -85,61 +99,74 @@ namespace MediaBrowser.Dlna.PlayTo
             {
             {
                 var uri = new Uri(location);
                 var uri = new Uri(location);
 
 
-                // TODO: Cache list of non-renderers by url to avoid repeating calls
+                lock (_nonRendererUrls)
+                {
+                    if (_nonRendererUrls.Contains(location, StringComparer.OrdinalIgnoreCase))
+                    {
+                        return;
+                    }
+                }
+
                 var device = await Device.CreateuPnpDeviceAsync(uri, _httpClient, _config, _logger).ConfigureAwait(false);
                 var device = await Device.CreateuPnpDeviceAsync(uri, _httpClient, _config, _logger).ConfigureAwait(false);
 
 
-                if (device.RendererCommands != null)
+                if (device.RendererCommands == null)
                 {
                 {
-                    var sessionInfo = await _sessionManager.LogSessionActivity(device.Properties.ClientType, _appHost.ApplicationVersion.ToString(), device.Properties.UUID, device.Properties.Name, uri.OriginalString, null)
-                        .ConfigureAwait(false);
+                    lock (_nonRendererUrls)
+                    {
+                        _nonRendererUrls.Add(location);
+                        return;
+                    }
+                }
+
+                var sessionInfo = await _sessionManager.LogSessionActivity(device.Properties.ClientType, _appHost.ApplicationVersion.ToString(), device.Properties.UUID, device.Properties.Name, uri.OriginalString, null)
+                    .ConfigureAwait(false);
 
 
-                    var controller = sessionInfo.SessionController as PlayToController;
+                var controller = sessionInfo.SessionController as PlayToController;
 
 
-                    if (controller == null)
+                if (controller == null)
+                {
+                    var serverAddress = GetServerAddress(localIp);
+                    string accessToken = null;
+
+                    sessionInfo.SessionController = controller = new PlayToController(sessionInfo,
+                        _sessionManager,
+                        _libraryManager,
+                        _logger,
+                        _dlnaManager,
+                        _userManager,
+                        _imageProcessor,
+                        serverAddress,
+                        accessToken,
+                        _deviceDiscovery,
+                        _userDataManager,
+                        _localization,
+                        _mediaSourceManager);
+
+                    controller.Init(device);
+
+                    var profile = _dlnaManager.GetProfile(device.Properties.ToDeviceIdentification()) ??
+                                  _dlnaManager.GetDefaultProfile();
+
+                    _sessionManager.ReportCapabilities(sessionInfo.Id, new ClientCapabilities
                     {
                     {
-                        var serverAddress = GetServerAddress(localIp);
-                        string accessToken = null;
-
-                        sessionInfo.SessionController = controller = new PlayToController(sessionInfo,
-                            _sessionManager,
-                            _libraryManager,
-                            _logger,
-                            _dlnaManager,
-                            _userManager,
-                            _imageProcessor,
-                            serverAddress,
-                            accessToken,
-                            _deviceDiscovery,
-                            _userDataManager,
-                            _localization,
-                            _mediaSourceManager);
-
-                        controller.Init(device);
-                        
-                        var profile = _dlnaManager.GetProfile(device.Properties.ToDeviceIdentification()) ??
-                                      _dlnaManager.GetDefaultProfile();
-
-                        _sessionManager.ReportCapabilities(sessionInfo.Id, new ClientCapabilities
+                        PlayableMediaTypes = profile.GetSupportedMediaTypes(),
+
+                        SupportedCommands = new List<string>
                         {
                         {
-                            PlayableMediaTypes = profile.GetSupportedMediaTypes(),
-
-                            SupportedCommands = new List<string>
-                            {
-                                GeneralCommandType.VolumeDown.ToString(),
-                                GeneralCommandType.VolumeUp.ToString(),
-                                GeneralCommandType.Mute.ToString(),
-                                GeneralCommandType.Unmute.ToString(),
-                                GeneralCommandType.ToggleMute.ToString(),
-                                GeneralCommandType.SetVolume.ToString(),
-                                GeneralCommandType.SetAudioStreamIndex.ToString(),
-                                GeneralCommandType.SetSubtitleStreamIndex.ToString()
-                            },
-
-                            SupportsMediaControl = true
-                        });
-
-                        _logger.Info("DLNA Session created for {0} - {1}", device.Properties.Name, device.Properties.ModelName);
-                    }
+                            GeneralCommandType.VolumeDown.ToString(),
+                            GeneralCommandType.VolumeUp.ToString(),
+                            GeneralCommandType.Mute.ToString(),
+                            GeneralCommandType.Unmute.ToString(),
+                            GeneralCommandType.ToggleMute.ToString(),
+                            GeneralCommandType.SetVolume.ToString(),
+                            GeneralCommandType.SetAudioStreamIndex.ToString(),
+                            GeneralCommandType.SetSubtitleStreamIndex.ToString()
+                        },
+
+                        SupportsMediaControl = true
+                    });
+
+                    _logger.Info("DLNA Session created for {0} - {1}", device.Properties.Name, device.Properties.ModelName);
                 }
                 }
             }
             }
             catch (Exception ex)
             catch (Exception ex)
@@ -156,6 +183,12 @@ namespace MediaBrowser.Dlna.PlayTo
         public void Dispose()
         public void Dispose()
         {
         {
             _deviceDiscovery.DeviceDiscovered -= _deviceDiscovery_DeviceDiscovered;
             _deviceDiscovery.DeviceDiscovered -= _deviceDiscovery_DeviceDiscovered;
+
+            if (_clearNonRenderersTimer != null)
+            {
+                _clearNonRenderersTimer.Dispose();
+                _clearNonRenderersTimer = null;
+            }
         }
         }
     }
     }
 }
 }

+ 8 - 8
MediaBrowser.Dlna/PlayTo/SsdpHttpClient.cs

@@ -1,7 +1,7 @@
-using System;
-using MediaBrowser.Common.Net;
+using MediaBrowser.Common.Net;
 using MediaBrowser.Controller.Configuration;
 using MediaBrowser.Controller.Configuration;
 using MediaBrowser.Dlna.Common;
 using MediaBrowser.Dlna.Common;
+using System;
 using System.Globalization;
 using System.Globalization;
 using System.IO;
 using System.IO;
 using System.Text;
 using System.Text;
@@ -13,7 +13,7 @@ namespace MediaBrowser.Dlna.PlayTo
     public class SsdpHttpClient
     public class SsdpHttpClient
     {
     {
         private const string USERAGENT = "Microsoft-Windows/6.2 UPnP/1.0 Microsoft-DLNA DLNADOC/1.50";
         private const string USERAGENT = "Microsoft-Windows/6.2 UPnP/1.0 Microsoft-DLNA DLNADOC/1.50";
-        private const string FriendlyName = "MediaBrowser";
+        private const string FriendlyName = "Emby";
 
 
         private readonly IHttpClient _httpClient;
         private readonly IHttpClient _httpClient;
         private readonly IServerConfigurationManager _config;
         private readonly IServerConfigurationManager _config;
@@ -28,9 +28,10 @@ namespace MediaBrowser.Dlna.PlayTo
             DeviceService service, 
             DeviceService service, 
             string command, 
             string command, 
             string postData, 
             string postData, 
+            bool logRequest = true,
             string header = null)
             string header = null)
         {
         {
-            var response = await PostSoapDataAsync(NormalizeServiceUrl(baseUrl, service.ControlUrl), "\"" + service.ServiceType + "#" + command + "\"", postData, header)
+            var response = await PostSoapDataAsync(NormalizeServiceUrl(baseUrl, service.ControlUrl), "\"" + service.ServiceType + "#" + command + "\"", postData, header, logRequest)
                 .ConfigureAwait(false);
                 .ConfigureAwait(false);
 
 
             using (var stream = response.Content)
             using (var stream = response.Content)
@@ -69,7 +70,6 @@ namespace MediaBrowser.Dlna.PlayTo
             {
             {
                 Url = url,
                 Url = url,
                 UserAgent = USERAGENT,
                 UserAgent = USERAGENT,
-                LogRequest = _config.GetDlnaConfiguration().EnableDebugLogging,
                 LogErrorResponseBody = true
                 LogErrorResponseBody = true
             };
             };
 
 
@@ -87,7 +87,6 @@ namespace MediaBrowser.Dlna.PlayTo
             {
             {
                 Url = url,
                 Url = url,
                 UserAgent = USERAGENT,
                 UserAgent = USERAGENT,
-                LogRequest = _config.GetDlnaConfiguration().EnableDebugLogging,
                 LogErrorResponseBody = true
                 LogErrorResponseBody = true
             };
             };
 
 
@@ -105,7 +104,8 @@ namespace MediaBrowser.Dlna.PlayTo
         private Task<HttpResponseInfo> PostSoapDataAsync(string url, 
         private Task<HttpResponseInfo> PostSoapDataAsync(string url, 
             string soapAction, 
             string soapAction, 
             string postData, 
             string postData, 
-            string header = null)
+            string header,
+            bool logRequest)
         {
         {
             if (!soapAction.StartsWith("\""))
             if (!soapAction.StartsWith("\""))
                 soapAction = "\"" + soapAction + "\"";
                 soapAction = "\"" + soapAction + "\"";
@@ -114,7 +114,7 @@ namespace MediaBrowser.Dlna.PlayTo
             {
             {
                 Url = url,
                 Url = url,
                 UserAgent = USERAGENT,
                 UserAgent = USERAGENT,
-                LogRequest = _config.GetDlnaConfiguration().EnableDebugLogging,
+                LogRequest = logRequest || _config.GetDlnaConfiguration().EnableDebugLogging,
                 LogErrorResponseBody = true
                 LogErrorResponseBody = true
             };
             };
 
 

+ 76 - 0
MediaBrowser.Dlna/Profiles/BubbleUpnpProfile.cs

@@ -0,0 +1,76 @@
+using System.Xml.Serialization;
+using MediaBrowser.Model.Dlna;
+
+namespace MediaBrowser.Dlna.Profiles
+{
+    [XmlRoot("Profile")]
+    public class BubbleUpnpProfile : DefaultProfile
+    {
+        public BubbleUpnpProfile()
+        {
+            Name = "BubbleUPnp";
+
+            TimelineOffsetSeconds = 5;
+
+            Identification = new DeviceIdentification
+            {
+                ModelName = "BubbleUPnp",
+
+                Headers = new[]
+                {
+                    new HttpHeaderInfo {Name = "User-Agent", Value = "BubbleUPnp", Match = HeaderMatchType.Substring}
+                }
+            };
+
+            TranscodingProfiles = new[]
+            {
+                new TranscodingProfile
+                {
+                    Container = "mp3",
+                    Type = DlnaProfileType.Audio,
+                    AudioCodec = "mp3"
+                },
+                new TranscodingProfile
+                {
+                    Container = "ts",
+                    Type = DlnaProfileType.Video,
+                    VideoCodec = "h264",
+                    AudioCodec = "aac"
+                },
+                new TranscodingProfile
+                {
+                    Container = "jpeg",
+                    Type = DlnaProfileType.Photo
+                }
+            };
+
+            DirectPlayProfiles = new[]
+            {
+                new DirectPlayProfile
+                {
+                    Container = "avi,mpeg,mkv,ts,mp4,mov,m4v,asf,webm,ogg,ogv,iso",
+                    Type = DlnaProfileType.Video
+                },
+
+                new DirectPlayProfile
+                {
+                    Container = "mp3,flac,asf,off,oga,aac",
+                    Type = DlnaProfileType.Audio
+                },
+
+                new DirectPlayProfile
+                {
+                    Type = DlnaProfileType.Photo,
+
+                    Container = "jpeg,png,gif,bmp,tiff"
+                }
+            };
+
+            ResponseProfiles = new ResponseProfile[] { };
+
+            ContainerProfiles = new ContainerProfile[] { };
+
+            CodecProfiles = new CodecProfile[] { };
+        }
+    }
+}

+ 18 - 0
MediaBrowser.Dlna/Profiles/DefaultProfile.cs

@@ -1,4 +1,5 @@
 using MediaBrowser.Model.Dlna;
 using MediaBrowser.Model.Dlna;
+using System.Linq;
 using System.Xml.Serialization;
 using System.Xml.Serialization;
 
 
 namespace MediaBrowser.Dlna.Profiles
 namespace MediaBrowser.Dlna.Profiles
@@ -75,6 +76,23 @@ namespace MediaBrowser.Dlna.Profiles
                     Type = DlnaProfileType.Video
                     Type = DlnaProfileType.Video
                 }
                 }
             };
             };
+
+            AddXmlRootAttribute("xmlns", "urn:schemas-upnp-org:device-1-0");
+            AddXmlRootAttribute("xmlns:dlna", "urn:schemas-dlna-org:device-1-0");
+        }
+
+        public void AddXmlRootAttribute(string name, string value)
+        {
+            var atts = XmlRootAttributes ?? new XmlAttribute[] { };
+            var list = atts.ToList();
+
+            list.Add(new XmlAttribute
+            {
+                Name = name,
+                Value = value
+            });
+
+            XmlRootAttributes = list.ToArray();
         }
         }
     }
     }
 }
 }

+ 1 - 8
MediaBrowser.Dlna/Profiles/PanasonicVieraProfile.cs

@@ -26,14 +26,7 @@ namespace MediaBrowser.Dlna.Profiles
                }
                }
             };
             };
 
 
-            XmlRootAttributes = new[]
-            {
-                new XmlAttribute
-                {
-                    Name = "xmlns:pv",
-                    Value = "http://www.pv.com/pvns/"
-                }
-            };
+            AddXmlRootAttribute("xmlns:pv", "http://www.pv.com/pvns/");
 
 
             TimelineOffsetSeconds = 10;
             TimelineOffsetSeconds = 10;
 
 

+ 1 - 8
MediaBrowser.Dlna/Profiles/SamsungSmartTvProfile.cs

@@ -27,14 +27,7 @@ namespace MediaBrowser.Dlna.Profiles
                 }
                 }
             };
             };
 
 
-            XmlRootAttributes = new[]
-            {
-                new XmlAttribute
-                {
-                    Name = "xmlns:sec",
-                    Value = "http://www.sec.co.kr/"
-                }
-            };
+            AddXmlRootAttribute("xmlns:sec", "http://www.sec.co.kr/");
 
 
             TranscodingProfiles = new[]
             TranscodingProfiles = new[]
            {
            {

+ 1 - 8
MediaBrowser.Dlna/Profiles/SonyBlurayPlayer2013Profile.cs

@@ -17,14 +17,7 @@ namespace MediaBrowser.Dlna.Profiles
                 ModelNumber = "BDP-2013"
                 ModelNumber = "BDP-2013"
             };
             };
 
 
-            XmlRootAttributes = new[]
-            {
-                new XmlAttribute
-                {
-                    Name = "xmlns:av",
-                    Value = "urn:schemas-sony-com:av"
-                }
-            };
+            AddXmlRootAttribute("xmlns:av", "urn:schemas-sony-com:av");
 
 
             ModelName = "Windows Media Player Sharing";
             ModelName = "Windows Media Player Sharing";
             ModelNumber = "3.0";
             ModelNumber = "3.0";

+ 1 - 8
MediaBrowser.Dlna/Profiles/SonyBlurayPlayerProfile.cs

@@ -33,14 +33,7 @@ namespace MediaBrowser.Dlna.Profiles
                 }
                 }
             };
             };
 
 
-            XmlRootAttributes = new[]
-            {
-                new XmlAttribute
-                {
-                    Name = "xmlns:av",
-                    Value = "urn:schemas-sony-com:av"
-                }
-            };
+            AddXmlRootAttribute("xmlns:av", "urn:schemas-sony-com:av");
 
 
             ModelName = "Windows Media Player Sharing";
             ModelName = "Windows Media Player Sharing";
             ModelNumber = "3.0";
             ModelNumber = "3.0";

+ 8 - 8
MediaBrowser.Dlna/Profiles/SonyBravia2010Profile.cs

@@ -26,14 +26,7 @@ namespace MediaBrowser.Dlna.Profiles
                 }
                 }
             };
             };
 
 
-            XmlRootAttributes = new[]
-            {
-                new XmlAttribute
-                {
-                    Name = "xmlns:av",
-                    Value = "urn:schemas-sony-com:av"
-                }
-            };
+            AddXmlRootAttribute("xmlns:av", "urn:schemas-sony-com:av");
 
 
             AlbumArtPn = "JPEG_TN";
             AlbumArtPn = "JPEG_TN";
 
 
@@ -47,6 +40,7 @@ namespace MediaBrowser.Dlna.Profiles
                 "http-get:*:audio/mpeg:DLNA.ORG_PN=MP3;DLNA.ORG_OP=01;DLNA.ORG_FLAGS=81500000000000000000000000000000,http-get:*:image/jpeg:DLNA.ORG_PN=JPEG_SM;DLNA.ORG_OP=00;DLNA.ORG_FLAGS=00D00000000000000000000000000000,http-get:*:video/mpeg:DLNA.ORG_PN=MPEG_PS_PAL;DLNA.ORG_OP=11;DLNA.ORG_FLAGS=81500000000000000000000000000000";
                 "http-get:*:audio/mpeg:DLNA.ORG_PN=MP3;DLNA.ORG_OP=01;DLNA.ORG_FLAGS=81500000000000000000000000000000,http-get:*:image/jpeg:DLNA.ORG_PN=JPEG_SM;DLNA.ORG_OP=00;DLNA.ORG_FLAGS=00D00000000000000000000000000000,http-get:*:video/mpeg:DLNA.ORG_PN=MPEG_PS_PAL;DLNA.ORG_OP=11;DLNA.ORG_FLAGS=81500000000000000000000000000000";
 
 
             EnableSingleAlbumArtLimit = true;
             EnableSingleAlbumArtLimit = true;
+            EnableAlbumArtInDidl = true;
             
             
             TranscodingProfiles = new[]
             TranscodingProfiles = new[]
             {
             {
@@ -293,6 +287,12 @@ namespace MediaBrowser.Dlna.Profiles
                             Condition = ProfileConditionType.LessThanEqual,
                             Condition = ProfileConditionType.LessThanEqual,
                             Property = ProfileConditionValue.Height,
                             Property = ProfileConditionValue.Height,
                             Value = "1080"
                             Value = "1080"
+                        },
+                        new ProfileCondition
+                        {
+                            Condition = ProfileConditionType.LessThanEqual,
+                            Property = ProfileConditionValue.VideoFramerate,
+                            Value = "30"
                         }
                         }
                     }
                     }
                 },
                 },

+ 8 - 8
MediaBrowser.Dlna/Profiles/SonyBravia2011Profile.cs

@@ -26,14 +26,7 @@ namespace MediaBrowser.Dlna.Profiles
                 }
                 }
             };
             };
 
 
-            XmlRootAttributes = new[]
-            {
-                new XmlAttribute
-                {
-                    Name = "xmlns:av",
-                    Value = "urn:schemas-sony-com:av"
-                }
-            };
+            AddXmlRootAttribute("xmlns:av", "urn:schemas-sony-com:av");
 
 
             AlbumArtPn = "JPEG_TN";
             AlbumArtPn = "JPEG_TN";
 
 
@@ -44,6 +37,7 @@ namespace MediaBrowser.Dlna.Profiles
             ManufacturerUrl = "http://www.microsoft.com/";
             ManufacturerUrl = "http://www.microsoft.com/";
             SonyAggregationFlags = "10";
             SonyAggregationFlags = "10";
             EnableSingleAlbumArtLimit = true;
             EnableSingleAlbumArtLimit = true;
+            EnableAlbumArtInDidl = true;
 
 
             TranscodingProfiles = new[]
             TranscodingProfiles = new[]
             {
             {
@@ -310,6 +304,12 @@ namespace MediaBrowser.Dlna.Profiles
                             Condition = ProfileConditionType.LessThanEqual,
                             Condition = ProfileConditionType.LessThanEqual,
                             Property = ProfileConditionValue.Height,
                             Property = ProfileConditionValue.Height,
                             Value = "1080"
                             Value = "1080"
+                        },
+                        new ProfileCondition
+                        {
+                            Condition = ProfileConditionType.LessThanEqual,
+                            Property = ProfileConditionValue.VideoFramerate,
+                            Value = "30"
                         }
                         }
                     }
                     }
                 },
                 },

+ 8 - 8
MediaBrowser.Dlna/Profiles/SonyBravia2012Profile.cs

@@ -26,14 +26,7 @@ namespace MediaBrowser.Dlna.Profiles
                 }
                 }
             };
             };
 
 
-            XmlRootAttributes = new[]
-            {
-                new XmlAttribute
-                {
-                    Name = "xmlns:av",
-                    Value = "urn:schemas-sony-com:av"
-                }
-            };
+            AddXmlRootAttribute("xmlns:av", "urn:schemas-sony-com:av");
 
 
             AlbumArtPn = "JPEG_TN";
             AlbumArtPn = "JPEG_TN";
 
 
@@ -44,6 +37,7 @@ namespace MediaBrowser.Dlna.Profiles
             ManufacturerUrl = "http://www.microsoft.com/";
             ManufacturerUrl = "http://www.microsoft.com/";
             SonyAggregationFlags = "10";
             SonyAggregationFlags = "10";
             EnableSingleAlbumArtLimit = true;
             EnableSingleAlbumArtLimit = true;
+            EnableAlbumArtInDidl = true;
 
 
             TranscodingProfiles = new[]
             TranscodingProfiles = new[]
             {
             {
@@ -250,6 +244,12 @@ namespace MediaBrowser.Dlna.Profiles
                             Condition = ProfileConditionType.LessThanEqual,
                             Condition = ProfileConditionType.LessThanEqual,
                             Property = ProfileConditionValue.Height,
                             Property = ProfileConditionValue.Height,
                             Value = "1080"
                             Value = "1080"
+                        },
+                        new ProfileCondition
+                        {
+                            Condition = ProfileConditionType.LessThanEqual,
+                            Property = ProfileConditionValue.VideoFramerate,
+                            Value = "30"
                         }
                         }
                     }
                     }
                 },
                 },

+ 8 - 8
MediaBrowser.Dlna/Profiles/SonyBravia2013Profile.cs

@@ -26,14 +26,7 @@ namespace MediaBrowser.Dlna.Profiles
                 }
                 }
             };
             };
 
 
-            XmlRootAttributes = new[]
-            {
-                new XmlAttribute
-                {
-                    Name = "xmlns:av",
-                    Value = "urn:schemas-sony-com:av"
-                }
-            };
+            AddXmlRootAttribute("xmlns:av", "urn:schemas-sony-com:av");
 
 
             AlbumArtPn = "JPEG_TN";
             AlbumArtPn = "JPEG_TN";
 
 
@@ -44,6 +37,7 @@ namespace MediaBrowser.Dlna.Profiles
             ManufacturerUrl = "http://www.microsoft.com/";
             ManufacturerUrl = "http://www.microsoft.com/";
             SonyAggregationFlags = "10";
             SonyAggregationFlags = "10";
             EnableSingleAlbumArtLimit = true;
             EnableSingleAlbumArtLimit = true;
+            EnableAlbumArtInDidl = true;
 
 
             TranscodingProfiles = new[]
             TranscodingProfiles = new[]
             {
             {
@@ -284,6 +278,12 @@ namespace MediaBrowser.Dlna.Profiles
                             Condition = ProfileConditionType.LessThanEqual,
                             Condition = ProfileConditionType.LessThanEqual,
                             Property = ProfileConditionValue.Height,
                             Property = ProfileConditionValue.Height,
                             Value = "1080"
                             Value = "1080"
+                        },
+                        new ProfileCondition
+                        {
+                            Condition = ProfileConditionType.LessThanEqual,
+                            Property = ProfileConditionValue.VideoFramerate,
+                            Value = "30"
                         }
                         }
                     }
                     }
                 }
                 }

+ 76 - 0
MediaBrowser.Dlna/Profiles/VlcProfile.cs

@@ -0,0 +1,76 @@
+using System.Xml.Serialization;
+using MediaBrowser.Model.Dlna;
+
+namespace MediaBrowser.Dlna.Profiles
+{
+    [XmlRoot("Profile")]
+    public class VlcProfile : DefaultProfile
+    {
+        public VlcProfile()
+        {
+            Name = "Vlc";
+
+            TimelineOffsetSeconds = 5;
+
+            Identification = new DeviceIdentification
+            {
+                ModelName = "Vlc",
+
+                Headers = new[]
+                {
+                    new HttpHeaderInfo {Name = "User-Agent", Value = "vlc", Match = HeaderMatchType.Substring}
+                }
+            };
+
+            TranscodingProfiles = new[]
+            {
+                new TranscodingProfile
+                {
+                    Container = "mp3",
+                    Type = DlnaProfileType.Audio,
+                    AudioCodec = "mp3"
+                },
+                new TranscodingProfile
+                {
+                    Container = "ts",
+                    Type = DlnaProfileType.Video,
+                    VideoCodec = "h264",
+                    AudioCodec = "aac"
+                },
+                new TranscodingProfile
+                {
+                    Container = "jpeg",
+                    Type = DlnaProfileType.Photo
+                }
+            };
+
+            DirectPlayProfiles = new[]
+            {
+                new DirectPlayProfile
+                {
+                    Container = "avi,mpeg,mkv,ts,mp4,mov,m4v,asf,webm,ogg,ogv,iso",
+                    Type = DlnaProfileType.Video
+                },
+
+                new DirectPlayProfile
+                {
+                    Container = "mp3,flac,asf,off,oga,aac",
+                    Type = DlnaProfileType.Audio
+                },
+
+                new DirectPlayProfile
+                {
+                    Type = DlnaProfileType.Photo,
+
+                    Container = "jpeg,png,gif,bmp,tiff"
+                }
+            };
+
+            ResponseProfiles = new ResponseProfile[] { };
+
+            ContainerProfiles = new ContainerProfile[] { };
+
+            CodecProfiles = new CodecProfile[] { };
+        }
+    }
+}

+ 0 - 1
MediaBrowser.Dlna/Profiles/WdtvLiveProfile.cs

@@ -11,7 +11,6 @@ namespace MediaBrowser.Dlna.Profiles
             Name = "WDTV Live";
             Name = "WDTV Live";
 
 
             TimelineOffsetSeconds = 5;
             TimelineOffsetSeconds = 5;
-            IgnoreTranscodeByteRangeRequests = true;
 
 
             Identification = new DeviceIdentification
             Identification = new DeviceIdentification
             {
             {

+ 7 - 3
MediaBrowser.Dlna/Profiles/Xbox360Profile.cs

@@ -18,12 +18,13 @@ namespace MediaBrowser.Dlna.Profiles
 
 
             ModelNumber = "12.0";
             ModelNumber = "12.0";
 
 
-            FriendlyName = "${HostName} : 1";
+            FriendlyName = "${HostName}: Emby:";
 
 
-            ModelUrl = "http://www.microsoft.com/";
+            ModelUrl = "http://go.microsoft.com/fwlink/?LinkId=105926";
             Manufacturer = "Microsoft Corporation";
             Manufacturer = "Microsoft Corporation";
-            ManufacturerUrl = "http://www.microsoft.com/";
+            ManufacturerUrl = "http://www.microsoft.com";
             XDlnaDoc = "DMS-1.50";
             XDlnaDoc = "DMS-1.50";
+            ModelDescription = null;
 
 
             TimelineOffsetSeconds = 40;
             TimelineOffsetSeconds = 40;
             RequiresPlainFolders = true;
             RequiresPlainFolders = true;
@@ -311,6 +312,9 @@ namespace MediaBrowser.Dlna.Profiles
                     }
                     }
                 }
                 }
             };
             };
+
+            XmlRootAttributes = new XmlAttribute[] { };
+            AddXmlRootAttribute("xmlns", "urn:schemas-upnp-org:device-1-0");
         }
         }
     }
     }
 }
 }

+ 1 - 1
MediaBrowser.Dlna/Profiles/XboxOneProfile.cs

@@ -14,7 +14,7 @@ namespace MediaBrowser.Dlna.Profiles
 
 
             Identification = new DeviceIdentification
             Identification = new DeviceIdentification
             {
             {
-                FriendlyName = "XboxOne",
+                ModelName = "Xbox One",
 
 
                 Headers = new[]
                 Headers = new[]
                 {
                 {

Những thai đổi đã bị hủy bỏ vì nó quá lớn
+ 29 - 0
MediaBrowser.Dlna/Profiles/Xml/BubbleUPnp.xml


+ 4 - 2
MediaBrowser.Dlna/Profiles/Xml/Default.xml

@@ -8,7 +8,6 @@
   <ModelDescription>Emby</ModelDescription>
   <ModelDescription>Emby</ModelDescription>
   <ModelNumber>Emby</ModelNumber>
   <ModelNumber>Emby</ModelNumber>
   <ModelUrl>http://emby.media/</ModelUrl>
   <ModelUrl>http://emby.media/</ModelUrl>
-  <IgnoreTranscodeByteRangeRequests>false</IgnoreTranscodeByteRangeRequests>
   <EnableAlbumArtInDidl>false</EnableAlbumArtInDidl>
   <EnableAlbumArtInDidl>false</EnableAlbumArtInDidl>
   <EnableSingleAlbumArtLimit>false</EnableSingleAlbumArtLimit>
   <EnableSingleAlbumArtLimit>false</EnableSingleAlbumArtLimit>
   <SupportedMediaTypes>Audio,Photo,Video</SupportedMediaTypes>
   <SupportedMediaTypes>Audio,Photo,Video</SupportedMediaTypes>
@@ -27,7 +26,10 @@
   <RequiresPlainVideoItems>false</RequiresPlainVideoItems>
   <RequiresPlainVideoItems>false</RequiresPlainVideoItems>
   <RequiresPlainFolders>false</RequiresPlainFolders>
   <RequiresPlainFolders>false</RequiresPlainFolders>
   <EnableMSMediaReceiverRegistrar>false</EnableMSMediaReceiverRegistrar>
   <EnableMSMediaReceiverRegistrar>false</EnableMSMediaReceiverRegistrar>
-  <XmlRootAttributes />
+  <XmlRootAttributes>
+    <XmlAttribute name="xmlns" value="urn:schemas-upnp-org:device-1-0" />
+    <XmlAttribute name="xmlns:dlna" value="urn:schemas-dlna-org:device-1-0" />
+  </XmlRootAttributes>
   <DirectPlayProfiles>
   <DirectPlayProfiles>
     <DirectPlayProfile container="mp3,wma" type="Audio" />
     <DirectPlayProfile container="mp3,wma" type="Audio" />
     <DirectPlayProfile container="avi,mp4" type="Video" />
     <DirectPlayProfile container="avi,mp4" type="Video" />

+ 4 - 2
MediaBrowser.Dlna/Profiles/Xml/Denon AVR.xml

@@ -13,7 +13,6 @@
   <ModelDescription>Emby</ModelDescription>
   <ModelDescription>Emby</ModelDescription>
   <ModelNumber>Emby</ModelNumber>
   <ModelNumber>Emby</ModelNumber>
   <ModelUrl>http://emby.media/</ModelUrl>
   <ModelUrl>http://emby.media/</ModelUrl>
-  <IgnoreTranscodeByteRangeRequests>false</IgnoreTranscodeByteRangeRequests>
   <EnableAlbumArtInDidl>false</EnableAlbumArtInDidl>
   <EnableAlbumArtInDidl>false</EnableAlbumArtInDidl>
   <EnableSingleAlbumArtLimit>false</EnableSingleAlbumArtLimit>
   <EnableSingleAlbumArtLimit>false</EnableSingleAlbumArtLimit>
   <SupportedMediaTypes>Audio,Photo,Video</SupportedMediaTypes>
   <SupportedMediaTypes>Audio,Photo,Video</SupportedMediaTypes>
@@ -32,7 +31,10 @@
   <RequiresPlainVideoItems>false</RequiresPlainVideoItems>
   <RequiresPlainVideoItems>false</RequiresPlainVideoItems>
   <RequiresPlainFolders>false</RequiresPlainFolders>
   <RequiresPlainFolders>false</RequiresPlainFolders>
   <EnableMSMediaReceiverRegistrar>false</EnableMSMediaReceiverRegistrar>
   <EnableMSMediaReceiverRegistrar>false</EnableMSMediaReceiverRegistrar>
-  <XmlRootAttributes />
+  <XmlRootAttributes>
+    <XmlAttribute name="xmlns" value="urn:schemas-upnp-org:device-1-0" />
+    <XmlAttribute name="xmlns:dlna" value="urn:schemas-dlna-org:device-1-0" />
+  </XmlRootAttributes>
   <DirectPlayProfiles>
   <DirectPlayProfiles>
     <DirectPlayProfile container="mp3,flac,m4a,wma" type="Audio" />
     <DirectPlayProfile container="mp3,flac,m4a,wma" type="Audio" />
   </DirectPlayProfiles>
   </DirectPlayProfiles>

+ 4 - 2
MediaBrowser.Dlna/Profiles/Xml/DirecTV HD-DVR.xml

@@ -14,7 +14,6 @@
   <ModelDescription>Emby</ModelDescription>
   <ModelDescription>Emby</ModelDescription>
   <ModelNumber>Emby</ModelNumber>
   <ModelNumber>Emby</ModelNumber>
   <ModelUrl>http://emby.media/</ModelUrl>
   <ModelUrl>http://emby.media/</ModelUrl>
-  <IgnoreTranscodeByteRangeRequests>false</IgnoreTranscodeByteRangeRequests>
   <EnableAlbumArtInDidl>false</EnableAlbumArtInDidl>
   <EnableAlbumArtInDidl>false</EnableAlbumArtInDidl>
   <EnableSingleAlbumArtLimit>false</EnableSingleAlbumArtLimit>
   <EnableSingleAlbumArtLimit>false</EnableSingleAlbumArtLimit>
   <SupportedMediaTypes>Audio,Photo,Video</SupportedMediaTypes>
   <SupportedMediaTypes>Audio,Photo,Video</SupportedMediaTypes>
@@ -33,7 +32,10 @@
   <RequiresPlainVideoItems>true</RequiresPlainVideoItems>
   <RequiresPlainVideoItems>true</RequiresPlainVideoItems>
   <RequiresPlainFolders>true</RequiresPlainFolders>
   <RequiresPlainFolders>true</RequiresPlainFolders>
   <EnableMSMediaReceiverRegistrar>false</EnableMSMediaReceiverRegistrar>
   <EnableMSMediaReceiverRegistrar>false</EnableMSMediaReceiverRegistrar>
-  <XmlRootAttributes />
+  <XmlRootAttributes>
+    <XmlAttribute name="xmlns" value="urn:schemas-upnp-org:device-1-0" />
+    <XmlAttribute name="xmlns:dlna" value="urn:schemas-dlna-org:device-1-0" />
+  </XmlRootAttributes>
   <DirectPlayProfiles>
   <DirectPlayProfiles>
     <DirectPlayProfile container="mpeg" audioCodec="mp2" videoCodec="mpeg2video" type="Video" />
     <DirectPlayProfile container="mpeg" audioCodec="mp2" videoCodec="mpeg2video" type="Video" />
     <DirectPlayProfile container="jpeg,jpg" type="Photo" />
     <DirectPlayProfile container="jpeg,jpg" type="Photo" />

+ 4 - 2
MediaBrowser.Dlna/Profiles/Xml/Dish Hopper-Joey.xml

@@ -15,7 +15,6 @@
   <ModelDescription>Emby</ModelDescription>
   <ModelDescription>Emby</ModelDescription>
   <ModelNumber>Emby</ModelNumber>
   <ModelNumber>Emby</ModelNumber>
   <ModelUrl>http://emby.media/</ModelUrl>
   <ModelUrl>http://emby.media/</ModelUrl>
-  <IgnoreTranscodeByteRangeRequests>false</IgnoreTranscodeByteRangeRequests>
   <EnableAlbumArtInDidl>false</EnableAlbumArtInDidl>
   <EnableAlbumArtInDidl>false</EnableAlbumArtInDidl>
   <EnableSingleAlbumArtLimit>false</EnableSingleAlbumArtLimit>
   <EnableSingleAlbumArtLimit>false</EnableSingleAlbumArtLimit>
   <SupportedMediaTypes>Audio,Photo,Video</SupportedMediaTypes>
   <SupportedMediaTypes>Audio,Photo,Video</SupportedMediaTypes>
@@ -34,7 +33,10 @@
   <RequiresPlainVideoItems>false</RequiresPlainVideoItems>
   <RequiresPlainVideoItems>false</RequiresPlainVideoItems>
   <RequiresPlainFolders>false</RequiresPlainFolders>
   <RequiresPlainFolders>false</RequiresPlainFolders>
   <EnableMSMediaReceiverRegistrar>false</EnableMSMediaReceiverRegistrar>
   <EnableMSMediaReceiverRegistrar>false</EnableMSMediaReceiverRegistrar>
-  <XmlRootAttributes />
+  <XmlRootAttributes>
+    <XmlAttribute name="xmlns" value="urn:schemas-upnp-org:device-1-0" />
+    <XmlAttribute name="xmlns:dlna" value="urn:schemas-dlna-org:device-1-0" />
+  </XmlRootAttributes>
   <DirectPlayProfiles>
   <DirectPlayProfiles>
     <DirectPlayProfile container="mp4,mkv,mpeg,ts" audioCodec="mp3,ac3,aac,he-aac,pcm" videoCodec="h264,mpeg2video" type="Video" />
     <DirectPlayProfile container="mp4,mkv,mpeg,ts" audioCodec="mp3,ac3,aac,he-aac,pcm" videoCodec="h264,mpeg2video" type="Video" />
     <DirectPlayProfile container="mp3" audioCodec="mp3" type="Audio" />
     <DirectPlayProfile container="mp3" audioCodec="mp3" type="Audio" />

Những thai đổi đã bị hủy bỏ vì nó quá lớn
+ 23 - 0
MediaBrowser.Dlna/Profiles/Xml/Generic Device.xml


+ 4 - 2
MediaBrowser.Dlna/Profiles/Xml/LG Smart TV.xml

@@ -14,7 +14,6 @@
   <ModelDescription>Emby</ModelDescription>
   <ModelDescription>Emby</ModelDescription>
   <ModelNumber>Emby</ModelNumber>
   <ModelNumber>Emby</ModelNumber>
   <ModelUrl>http://emby.media/</ModelUrl>
   <ModelUrl>http://emby.media/</ModelUrl>
-  <IgnoreTranscodeByteRangeRequests>false</IgnoreTranscodeByteRangeRequests>
   <EnableAlbumArtInDidl>false</EnableAlbumArtInDidl>
   <EnableAlbumArtInDidl>false</EnableAlbumArtInDidl>
   <EnableSingleAlbumArtLimit>false</EnableSingleAlbumArtLimit>
   <EnableSingleAlbumArtLimit>false</EnableSingleAlbumArtLimit>
   <SupportedMediaTypes>Audio,Photo,Video</SupportedMediaTypes>
   <SupportedMediaTypes>Audio,Photo,Video</SupportedMediaTypes>
@@ -33,7 +32,10 @@
   <RequiresPlainVideoItems>false</RequiresPlainVideoItems>
   <RequiresPlainVideoItems>false</RequiresPlainVideoItems>
   <RequiresPlainFolders>false</RequiresPlainFolders>
   <RequiresPlainFolders>false</RequiresPlainFolders>
   <EnableMSMediaReceiverRegistrar>false</EnableMSMediaReceiverRegistrar>
   <EnableMSMediaReceiverRegistrar>false</EnableMSMediaReceiverRegistrar>
-  <XmlRootAttributes />
+  <XmlRootAttributes>
+    <XmlAttribute name="xmlns" value="urn:schemas-upnp-org:device-1-0" />
+    <XmlAttribute name="xmlns:dlna" value="urn:schemas-dlna-org:device-1-0" />
+  </XmlRootAttributes>
   <DirectPlayProfiles>
   <DirectPlayProfiles>
     <DirectPlayProfile container="ts" audioCodec="aac,ac3,mp3" videoCodec="h264" type="Video" />
     <DirectPlayProfile container="ts" audioCodec="aac,ac3,mp3" videoCodec="h264" type="Video" />
     <DirectPlayProfile container="mkv" audioCodec="aac,ac3,mp3" videoCodec="h264" type="Video" />
     <DirectPlayProfile container="mkv" audioCodec="aac,ac3,mp3" videoCodec="h264" type="Video" />

+ 4 - 2
MediaBrowser.Dlna/Profiles/Xml/Linksys DMA2100.xml

@@ -12,7 +12,6 @@
   <ModelDescription>Emby</ModelDescription>
   <ModelDescription>Emby</ModelDescription>
   <ModelNumber>Emby</ModelNumber>
   <ModelNumber>Emby</ModelNumber>
   <ModelUrl>http://emby.media/</ModelUrl>
   <ModelUrl>http://emby.media/</ModelUrl>
-  <IgnoreTranscodeByteRangeRequests>false</IgnoreTranscodeByteRangeRequests>
   <EnableAlbumArtInDidl>false</EnableAlbumArtInDidl>
   <EnableAlbumArtInDidl>false</EnableAlbumArtInDidl>
   <EnableSingleAlbumArtLimit>false</EnableSingleAlbumArtLimit>
   <EnableSingleAlbumArtLimit>false</EnableSingleAlbumArtLimit>
   <SupportedMediaTypes>Audio,Photo,Video</SupportedMediaTypes>
   <SupportedMediaTypes>Audio,Photo,Video</SupportedMediaTypes>
@@ -31,7 +30,10 @@
   <RequiresPlainVideoItems>false</RequiresPlainVideoItems>
   <RequiresPlainVideoItems>false</RequiresPlainVideoItems>
   <RequiresPlainFolders>false</RequiresPlainFolders>
   <RequiresPlainFolders>false</RequiresPlainFolders>
   <EnableMSMediaReceiverRegistrar>false</EnableMSMediaReceiverRegistrar>
   <EnableMSMediaReceiverRegistrar>false</EnableMSMediaReceiverRegistrar>
-  <XmlRootAttributes />
+  <XmlRootAttributes>
+    <XmlAttribute name="xmlns" value="urn:schemas-upnp-org:device-1-0" />
+    <XmlAttribute name="xmlns:dlna" value="urn:schemas-dlna-org:device-1-0" />
+  </XmlRootAttributes>
   <DirectPlayProfiles>
   <DirectPlayProfiles>
     <DirectPlayProfile container="mp3,flac,m4a,wma" type="Audio" />
     <DirectPlayProfile container="mp3,flac,m4a,wma" type="Audio" />
     <DirectPlayProfile container="avi,mp4,mkv,ts" type="Video" />
     <DirectPlayProfile container="avi,mp4,mkv,ts" type="Video" />

+ 4 - 2
MediaBrowser.Dlna/Profiles/Xml/MediaMonkey.xml

@@ -14,7 +14,6 @@
   <ModelDescription>Emby</ModelDescription>
   <ModelDescription>Emby</ModelDescription>
   <ModelNumber>Emby</ModelNumber>
   <ModelNumber>Emby</ModelNumber>
   <ModelUrl>http://emby.media/</ModelUrl>
   <ModelUrl>http://emby.media/</ModelUrl>
-  <IgnoreTranscodeByteRangeRequests>false</IgnoreTranscodeByteRangeRequests>
   <EnableAlbumArtInDidl>false</EnableAlbumArtInDidl>
   <EnableAlbumArtInDidl>false</EnableAlbumArtInDidl>
   <EnableSingleAlbumArtLimit>false</EnableSingleAlbumArtLimit>
   <EnableSingleAlbumArtLimit>false</EnableSingleAlbumArtLimit>
   <SupportedMediaTypes>Audio</SupportedMediaTypes>
   <SupportedMediaTypes>Audio</SupportedMediaTypes>
@@ -33,7 +32,10 @@
   <RequiresPlainVideoItems>false</RequiresPlainVideoItems>
   <RequiresPlainVideoItems>false</RequiresPlainVideoItems>
   <RequiresPlainFolders>false</RequiresPlainFolders>
   <RequiresPlainFolders>false</RequiresPlainFolders>
   <EnableMSMediaReceiverRegistrar>false</EnableMSMediaReceiverRegistrar>
   <EnableMSMediaReceiverRegistrar>false</EnableMSMediaReceiverRegistrar>
-  <XmlRootAttributes />
+  <XmlRootAttributes>
+    <XmlAttribute name="xmlns" value="urn:schemas-upnp-org:device-1-0" />
+    <XmlAttribute name="xmlns:dlna" value="urn:schemas-dlna-org:device-1-0" />
+  </XmlRootAttributes>
   <DirectPlayProfiles>
   <DirectPlayProfiles>
     <DirectPlayProfile container="mp3" audioCodec="mp2,mp3" type="Audio" />
     <DirectPlayProfile container="mp3" audioCodec="mp2,mp3" type="Audio" />
     <DirectPlayProfile container="mp4" audioCodec="mp4" type="Audio" />
     <DirectPlayProfile container="mp4" audioCodec="mp4" type="Audio" />

+ 2 - 1
MediaBrowser.Dlna/Profiles/Xml/Panasonic Viera.xml

@@ -15,7 +15,6 @@
   <ModelDescription>Emby</ModelDescription>
   <ModelDescription>Emby</ModelDescription>
   <ModelNumber>Emby</ModelNumber>
   <ModelNumber>Emby</ModelNumber>
   <ModelUrl>http://emby.media/</ModelUrl>
   <ModelUrl>http://emby.media/</ModelUrl>
-  <IgnoreTranscodeByteRangeRequests>false</IgnoreTranscodeByteRangeRequests>
   <EnableAlbumArtInDidl>false</EnableAlbumArtInDidl>
   <EnableAlbumArtInDidl>false</EnableAlbumArtInDidl>
   <EnableSingleAlbumArtLimit>false</EnableSingleAlbumArtLimit>
   <EnableSingleAlbumArtLimit>false</EnableSingleAlbumArtLimit>
   <SupportedMediaTypes>Audio,Photo,Video</SupportedMediaTypes>
   <SupportedMediaTypes>Audio,Photo,Video</SupportedMediaTypes>
@@ -35,6 +34,8 @@
   <RequiresPlainFolders>false</RequiresPlainFolders>
   <RequiresPlainFolders>false</RequiresPlainFolders>
   <EnableMSMediaReceiverRegistrar>false</EnableMSMediaReceiverRegistrar>
   <EnableMSMediaReceiverRegistrar>false</EnableMSMediaReceiverRegistrar>
   <XmlRootAttributes>
   <XmlRootAttributes>
+    <XmlAttribute name="xmlns" value="urn:schemas-upnp-org:device-1-0" />
+    <XmlAttribute name="xmlns:dlna" value="urn:schemas-dlna-org:device-1-0" />
     <XmlAttribute name="xmlns:pv" value="http://www.pv.com/pvns/" />
     <XmlAttribute name="xmlns:pv" value="http://www.pv.com/pvns/" />
   </XmlRootAttributes>
   </XmlRootAttributes>
   <DirectPlayProfiles>
   <DirectPlayProfiles>

+ 4 - 2
MediaBrowser.Dlna/Profiles/Xml/Popcorn Hour.xml

@@ -8,7 +8,6 @@
   <ModelDescription>Emby</ModelDescription>
   <ModelDescription>Emby</ModelDescription>
   <ModelNumber>Emby</ModelNumber>
   <ModelNumber>Emby</ModelNumber>
   <ModelUrl>http://emby.media/</ModelUrl>
   <ModelUrl>http://emby.media/</ModelUrl>
-  <IgnoreTranscodeByteRangeRequests>false</IgnoreTranscodeByteRangeRequests>
   <EnableAlbumArtInDidl>false</EnableAlbumArtInDidl>
   <EnableAlbumArtInDidl>false</EnableAlbumArtInDidl>
   <EnableSingleAlbumArtLimit>false</EnableSingleAlbumArtLimit>
   <EnableSingleAlbumArtLimit>false</EnableSingleAlbumArtLimit>
   <SupportedMediaTypes>Audio,Photo,Video</SupportedMediaTypes>
   <SupportedMediaTypes>Audio,Photo,Video</SupportedMediaTypes>
@@ -27,7 +26,10 @@
   <RequiresPlainVideoItems>false</RequiresPlainVideoItems>
   <RequiresPlainVideoItems>false</RequiresPlainVideoItems>
   <RequiresPlainFolders>false</RequiresPlainFolders>
   <RequiresPlainFolders>false</RequiresPlainFolders>
   <EnableMSMediaReceiverRegistrar>false</EnableMSMediaReceiverRegistrar>
   <EnableMSMediaReceiverRegistrar>false</EnableMSMediaReceiverRegistrar>
-  <XmlRootAttributes />
+  <XmlRootAttributes>
+    <XmlAttribute name="xmlns" value="urn:schemas-upnp-org:device-1-0" />
+    <XmlAttribute name="xmlns:dlna" value="urn:schemas-dlna-org:device-1-0" />
+  </XmlRootAttributes>
   <DirectPlayProfiles>
   <DirectPlayProfiles>
     <DirectPlayProfile container="mp4,mov" audioCodec="aac" videoCodec="h264,mpeg4" type="Video" />
     <DirectPlayProfile container="mp4,mov" audioCodec="aac" videoCodec="h264,mpeg4" type="Video" />
     <DirectPlayProfile container="ts" audioCodec="aac,ac3,eac3,mp3,mp2,pcm" videoCodec="h264" type="Video" />
     <DirectPlayProfile container="ts" audioCodec="aac,ac3,eac3,mp3,mp2,pcm" videoCodec="h264" type="Video" />

+ 2 - 1
MediaBrowser.Dlna/Profiles/Xml/Samsung Smart TV.xml

@@ -14,7 +14,6 @@
   <ModelDescription>Emby</ModelDescription>
   <ModelDescription>Emby</ModelDescription>
   <ModelNumber>Emby</ModelNumber>
   <ModelNumber>Emby</ModelNumber>
   <ModelUrl>http://emby.media/</ModelUrl>
   <ModelUrl>http://emby.media/</ModelUrl>
-  <IgnoreTranscodeByteRangeRequests>false</IgnoreTranscodeByteRangeRequests>
   <EnableAlbumArtInDidl>true</EnableAlbumArtInDidl>
   <EnableAlbumArtInDidl>true</EnableAlbumArtInDidl>
   <EnableSingleAlbumArtLimit>false</EnableSingleAlbumArtLimit>
   <EnableSingleAlbumArtLimit>false</EnableSingleAlbumArtLimit>
   <SupportedMediaTypes>Audio,Photo,Video</SupportedMediaTypes>
   <SupportedMediaTypes>Audio,Photo,Video</SupportedMediaTypes>
@@ -34,6 +33,8 @@
   <RequiresPlainFolders>false</RequiresPlainFolders>
   <RequiresPlainFolders>false</RequiresPlainFolders>
   <EnableMSMediaReceiverRegistrar>false</EnableMSMediaReceiverRegistrar>
   <EnableMSMediaReceiverRegistrar>false</EnableMSMediaReceiverRegistrar>
   <XmlRootAttributes>
   <XmlRootAttributes>
+    <XmlAttribute name="xmlns" value="urn:schemas-upnp-org:device-1-0" />
+    <XmlAttribute name="xmlns:dlna" value="urn:schemas-dlna-org:device-1-0" />
     <XmlAttribute name="xmlns:sec" value="http://www.sec.co.kr/" />
     <XmlAttribute name="xmlns:sec" value="http://www.sec.co.kr/" />
   </XmlRootAttributes>
   </XmlRootAttributes>
   <DirectPlayProfiles>
   <DirectPlayProfiles>

+ 2 - 1
MediaBrowser.Dlna/Profiles/Xml/Sony Blu-ray Player 2013.xml

@@ -14,7 +14,6 @@
   <ModelDescription>Emby</ModelDescription>
   <ModelDescription>Emby</ModelDescription>
   <ModelNumber>3.0</ModelNumber>
   <ModelNumber>3.0</ModelNumber>
   <ModelUrl>http://emby.media/</ModelUrl>
   <ModelUrl>http://emby.media/</ModelUrl>
-  <IgnoreTranscodeByteRangeRequests>false</IgnoreTranscodeByteRangeRequests>
   <EnableAlbumArtInDidl>false</EnableAlbumArtInDidl>
   <EnableAlbumArtInDidl>false</EnableAlbumArtInDidl>
   <EnableSingleAlbumArtLimit>false</EnableSingleAlbumArtLimit>
   <EnableSingleAlbumArtLimit>false</EnableSingleAlbumArtLimit>
   <SupportedMediaTypes>Audio,Photo,Video</SupportedMediaTypes>
   <SupportedMediaTypes>Audio,Photo,Video</SupportedMediaTypes>
@@ -34,6 +33,8 @@
   <RequiresPlainFolders>false</RequiresPlainFolders>
   <RequiresPlainFolders>false</RequiresPlainFolders>
   <EnableMSMediaReceiverRegistrar>false</EnableMSMediaReceiverRegistrar>
   <EnableMSMediaReceiverRegistrar>false</EnableMSMediaReceiverRegistrar>
   <XmlRootAttributes>
   <XmlRootAttributes>
+    <XmlAttribute name="xmlns" value="urn:schemas-upnp-org:device-1-0" />
+    <XmlAttribute name="xmlns:dlna" value="urn:schemas-dlna-org:device-1-0" />
     <XmlAttribute name="xmlns:av" value="urn:schemas-sony-com:av" />
     <XmlAttribute name="xmlns:av" value="urn:schemas-sony-com:av" />
   </XmlRootAttributes>
   </XmlRootAttributes>
   <DirectPlayProfiles>
   <DirectPlayProfiles>

+ 2 - 1
MediaBrowser.Dlna/Profiles/Xml/Sony Blu-ray Player.xml

@@ -16,7 +16,6 @@
   <ModelDescription>Emby</ModelDescription>
   <ModelDescription>Emby</ModelDescription>
   <ModelNumber>3.0</ModelNumber>
   <ModelNumber>3.0</ModelNumber>
   <ModelUrl>http://emby.media/</ModelUrl>
   <ModelUrl>http://emby.media/</ModelUrl>
-  <IgnoreTranscodeByteRangeRequests>false</IgnoreTranscodeByteRangeRequests>
   <EnableAlbumArtInDidl>false</EnableAlbumArtInDidl>
   <EnableAlbumArtInDidl>false</EnableAlbumArtInDidl>
   <EnableSingleAlbumArtLimit>false</EnableSingleAlbumArtLimit>
   <EnableSingleAlbumArtLimit>false</EnableSingleAlbumArtLimit>
   <SupportedMediaTypes>Audio,Photo,Video</SupportedMediaTypes>
   <SupportedMediaTypes>Audio,Photo,Video</SupportedMediaTypes>
@@ -36,6 +35,8 @@
   <RequiresPlainFolders>false</RequiresPlainFolders>
   <RequiresPlainFolders>false</RequiresPlainFolders>
   <EnableMSMediaReceiverRegistrar>false</EnableMSMediaReceiverRegistrar>
   <EnableMSMediaReceiverRegistrar>false</EnableMSMediaReceiverRegistrar>
   <XmlRootAttributes>
   <XmlRootAttributes>
+    <XmlAttribute name="xmlns" value="urn:schemas-upnp-org:device-1-0" />
+    <XmlAttribute name="xmlns:dlna" value="urn:schemas-dlna-org:device-1-0" />
     <XmlAttribute name="xmlns:av" value="urn:schemas-sony-com:av" />
     <XmlAttribute name="xmlns:av" value="urn:schemas-sony-com:av" />
   </XmlRootAttributes>
   </XmlRootAttributes>
   <DirectPlayProfiles>
   <DirectPlayProfiles>

+ 4 - 2
MediaBrowser.Dlna/Profiles/Xml/Sony Bravia (2010).xml

@@ -15,8 +15,7 @@
   <ModelDescription>Emby</ModelDescription>
   <ModelDescription>Emby</ModelDescription>
   <ModelNumber>3.0</ModelNumber>
   <ModelNumber>3.0</ModelNumber>
   <ModelUrl>http://www.microsoft.com/</ModelUrl>
   <ModelUrl>http://www.microsoft.com/</ModelUrl>
-  <IgnoreTranscodeByteRangeRequests>false</IgnoreTranscodeByteRangeRequests>
-  <EnableAlbumArtInDidl>false</EnableAlbumArtInDidl>
+  <EnableAlbumArtInDidl>true</EnableAlbumArtInDidl>
   <EnableSingleAlbumArtLimit>true</EnableSingleAlbumArtLimit>
   <EnableSingleAlbumArtLimit>true</EnableSingleAlbumArtLimit>
   <SupportedMediaTypes>Audio,Photo,Video</SupportedMediaTypes>
   <SupportedMediaTypes>Audio,Photo,Video</SupportedMediaTypes>
   <AlbumArtPn>JPEG_TN</AlbumArtPn>
   <AlbumArtPn>JPEG_TN</AlbumArtPn>
@@ -36,6 +35,8 @@
   <RequiresPlainFolders>false</RequiresPlainFolders>
   <RequiresPlainFolders>false</RequiresPlainFolders>
   <EnableMSMediaReceiverRegistrar>false</EnableMSMediaReceiverRegistrar>
   <EnableMSMediaReceiverRegistrar>false</EnableMSMediaReceiverRegistrar>
   <XmlRootAttributes>
   <XmlRootAttributes>
+    <XmlAttribute name="xmlns" value="urn:schemas-upnp-org:device-1-0" />
+    <XmlAttribute name="xmlns:dlna" value="urn:schemas-dlna-org:device-1-0" />
     <XmlAttribute name="xmlns:av" value="urn:schemas-sony-com:av" />
     <XmlAttribute name="xmlns:av" value="urn:schemas-sony-com:av" />
   </XmlRootAttributes>
   </XmlRootAttributes>
   <DirectPlayProfiles>
   <DirectPlayProfiles>
@@ -79,6 +80,7 @@
       <Conditions>
       <Conditions>
         <ProfileCondition condition="LessThanEqual" property="Width" value="1920" isRequired="true" />
         <ProfileCondition condition="LessThanEqual" property="Width" value="1920" isRequired="true" />
         <ProfileCondition condition="LessThanEqual" property="Height" value="1080" isRequired="true" />
         <ProfileCondition condition="LessThanEqual" property="Height" value="1080" isRequired="true" />
+        <ProfileCondition condition="LessThanEqual" property="VideoFramerate" value="30" isRequired="true" />
       </Conditions>
       </Conditions>
     </CodecProfile>
     </CodecProfile>
     <CodecProfile type="VideoAudio" codec="ac3">
     <CodecProfile type="VideoAudio" codec="ac3">

+ 4 - 2
MediaBrowser.Dlna/Profiles/Xml/Sony Bravia (2011).xml

@@ -15,8 +15,7 @@
   <ModelDescription>Emby</ModelDescription>
   <ModelDescription>Emby</ModelDescription>
   <ModelNumber>3.0</ModelNumber>
   <ModelNumber>3.0</ModelNumber>
   <ModelUrl>http://www.microsoft.com/</ModelUrl>
   <ModelUrl>http://www.microsoft.com/</ModelUrl>
-  <IgnoreTranscodeByteRangeRequests>false</IgnoreTranscodeByteRangeRequests>
-  <EnableAlbumArtInDidl>false</EnableAlbumArtInDidl>
+  <EnableAlbumArtInDidl>true</EnableAlbumArtInDidl>
   <EnableSingleAlbumArtLimit>true</EnableSingleAlbumArtLimit>
   <EnableSingleAlbumArtLimit>true</EnableSingleAlbumArtLimit>
   <SupportedMediaTypes>Audio,Photo,Video</SupportedMediaTypes>
   <SupportedMediaTypes>Audio,Photo,Video</SupportedMediaTypes>
   <AlbumArtPn>JPEG_TN</AlbumArtPn>
   <AlbumArtPn>JPEG_TN</AlbumArtPn>
@@ -36,6 +35,8 @@
   <RequiresPlainFolders>false</RequiresPlainFolders>
   <RequiresPlainFolders>false</RequiresPlainFolders>
   <EnableMSMediaReceiverRegistrar>false</EnableMSMediaReceiverRegistrar>
   <EnableMSMediaReceiverRegistrar>false</EnableMSMediaReceiverRegistrar>
   <XmlRootAttributes>
   <XmlRootAttributes>
+    <XmlAttribute name="xmlns" value="urn:schemas-upnp-org:device-1-0" />
+    <XmlAttribute name="xmlns:dlna" value="urn:schemas-dlna-org:device-1-0" />
     <XmlAttribute name="xmlns:av" value="urn:schemas-sony-com:av" />
     <XmlAttribute name="xmlns:av" value="urn:schemas-sony-com:av" />
   </XmlRootAttributes>
   </XmlRootAttributes>
   <DirectPlayProfiles>
   <DirectPlayProfiles>
@@ -82,6 +83,7 @@
       <Conditions>
       <Conditions>
         <ProfileCondition condition="LessThanEqual" property="Width" value="1920" isRequired="true" />
         <ProfileCondition condition="LessThanEqual" property="Width" value="1920" isRequired="true" />
         <ProfileCondition condition="LessThanEqual" property="Height" value="1080" isRequired="true" />
         <ProfileCondition condition="LessThanEqual" property="Height" value="1080" isRequired="true" />
+        <ProfileCondition condition="LessThanEqual" property="VideoFramerate" value="30" isRequired="true" />
       </Conditions>
       </Conditions>
     </CodecProfile>
     </CodecProfile>
     <CodecProfile type="VideoAudio" codec="ac3">
     <CodecProfile type="VideoAudio" codec="ac3">

+ 4 - 2
MediaBrowser.Dlna/Profiles/Xml/Sony Bravia (2012).xml

@@ -15,8 +15,7 @@
   <ModelDescription>Emby</ModelDescription>
   <ModelDescription>Emby</ModelDescription>
   <ModelNumber>3.0</ModelNumber>
   <ModelNumber>3.0</ModelNumber>
   <ModelUrl>http://www.microsoft.com/</ModelUrl>
   <ModelUrl>http://www.microsoft.com/</ModelUrl>
-  <IgnoreTranscodeByteRangeRequests>false</IgnoreTranscodeByteRangeRequests>
-  <EnableAlbumArtInDidl>false</EnableAlbumArtInDidl>
+  <EnableAlbumArtInDidl>true</EnableAlbumArtInDidl>
   <EnableSingleAlbumArtLimit>true</EnableSingleAlbumArtLimit>
   <EnableSingleAlbumArtLimit>true</EnableSingleAlbumArtLimit>
   <SupportedMediaTypes>Audio,Photo,Video</SupportedMediaTypes>
   <SupportedMediaTypes>Audio,Photo,Video</SupportedMediaTypes>
   <AlbumArtPn>JPEG_TN</AlbumArtPn>
   <AlbumArtPn>JPEG_TN</AlbumArtPn>
@@ -36,6 +35,8 @@
   <RequiresPlainFolders>false</RequiresPlainFolders>
   <RequiresPlainFolders>false</RequiresPlainFolders>
   <EnableMSMediaReceiverRegistrar>false</EnableMSMediaReceiverRegistrar>
   <EnableMSMediaReceiverRegistrar>false</EnableMSMediaReceiverRegistrar>
   <XmlRootAttributes>
   <XmlRootAttributes>
+    <XmlAttribute name="xmlns" value="urn:schemas-upnp-org:device-1-0" />
+    <XmlAttribute name="xmlns:dlna" value="urn:schemas-dlna-org:device-1-0" />
     <XmlAttribute name="xmlns:av" value="urn:schemas-sony-com:av" />
     <XmlAttribute name="xmlns:av" value="urn:schemas-sony-com:av" />
   </XmlRootAttributes>
   </XmlRootAttributes>
   <DirectPlayProfiles>
   <DirectPlayProfiles>
@@ -67,6 +68,7 @@
       <Conditions>
       <Conditions>
         <ProfileCondition condition="LessThanEqual" property="Width" value="1920" isRequired="true" />
         <ProfileCondition condition="LessThanEqual" property="Width" value="1920" isRequired="true" />
         <ProfileCondition condition="LessThanEqual" property="Height" value="1080" isRequired="true" />
         <ProfileCondition condition="LessThanEqual" property="Height" value="1080" isRequired="true" />
+        <ProfileCondition condition="LessThanEqual" property="VideoFramerate" value="30" isRequired="true" />
       </Conditions>
       </Conditions>
     </CodecProfile>
     </CodecProfile>
     <CodecProfile type="VideoAudio" codec="ac3">
     <CodecProfile type="VideoAudio" codec="ac3">

+ 4 - 2
MediaBrowser.Dlna/Profiles/Xml/Sony Bravia (2013).xml

@@ -15,8 +15,7 @@
   <ModelDescription>Emby</ModelDescription>
   <ModelDescription>Emby</ModelDescription>
   <ModelNumber>3.0</ModelNumber>
   <ModelNumber>3.0</ModelNumber>
   <ModelUrl>http://www.microsoft.com/</ModelUrl>
   <ModelUrl>http://www.microsoft.com/</ModelUrl>
-  <IgnoreTranscodeByteRangeRequests>false</IgnoreTranscodeByteRangeRequests>
-  <EnableAlbumArtInDidl>false</EnableAlbumArtInDidl>
+  <EnableAlbumArtInDidl>true</EnableAlbumArtInDidl>
   <EnableSingleAlbumArtLimit>true</EnableSingleAlbumArtLimit>
   <EnableSingleAlbumArtLimit>true</EnableSingleAlbumArtLimit>
   <SupportedMediaTypes>Audio,Photo,Video</SupportedMediaTypes>
   <SupportedMediaTypes>Audio,Photo,Video</SupportedMediaTypes>
   <AlbumArtPn>JPEG_TN</AlbumArtPn>
   <AlbumArtPn>JPEG_TN</AlbumArtPn>
@@ -36,6 +35,8 @@
   <RequiresPlainFolders>false</RequiresPlainFolders>
   <RequiresPlainFolders>false</RequiresPlainFolders>
   <EnableMSMediaReceiverRegistrar>false</EnableMSMediaReceiverRegistrar>
   <EnableMSMediaReceiverRegistrar>false</EnableMSMediaReceiverRegistrar>
   <XmlRootAttributes>
   <XmlRootAttributes>
+    <XmlAttribute name="xmlns" value="urn:schemas-upnp-org:device-1-0" />
+    <XmlAttribute name="xmlns:dlna" value="urn:schemas-dlna-org:device-1-0" />
     <XmlAttribute name="xmlns:av" value="urn:schemas-sony-com:av" />
     <XmlAttribute name="xmlns:av" value="urn:schemas-sony-com:av" />
   </XmlRootAttributes>
   </XmlRootAttributes>
   <DirectPlayProfiles>
   <DirectPlayProfiles>
@@ -72,6 +73,7 @@
       <Conditions>
       <Conditions>
         <ProfileCondition condition="LessThanEqual" property="Width" value="1920" isRequired="true" />
         <ProfileCondition condition="LessThanEqual" property="Width" value="1920" isRequired="true" />
         <ProfileCondition condition="LessThanEqual" property="Height" value="1080" isRequired="true" />
         <ProfileCondition condition="LessThanEqual" property="Height" value="1080" isRequired="true" />
+        <ProfileCondition condition="LessThanEqual" property="VideoFramerate" value="30" isRequired="true" />
       </Conditions>
       </Conditions>
     </CodecProfile>
     </CodecProfile>
   </CodecProfiles>
   </CodecProfiles>

+ 4 - 2
MediaBrowser.Dlna/Profiles/Xml/Sony PlayStation 3.xml

@@ -15,7 +15,6 @@
   <ModelDescription>Emby</ModelDescription>
   <ModelDescription>Emby</ModelDescription>
   <ModelNumber>Emby</ModelNumber>
   <ModelNumber>Emby</ModelNumber>
   <ModelUrl>http://emby.media/</ModelUrl>
   <ModelUrl>http://emby.media/</ModelUrl>
-  <IgnoreTranscodeByteRangeRequests>false</IgnoreTranscodeByteRangeRequests>
   <EnableAlbumArtInDidl>false</EnableAlbumArtInDidl>
   <EnableAlbumArtInDidl>false</EnableAlbumArtInDidl>
   <EnableSingleAlbumArtLimit>true</EnableSingleAlbumArtLimit>
   <EnableSingleAlbumArtLimit>true</EnableSingleAlbumArtLimit>
   <SupportedMediaTypes>Audio,Photo,Video</SupportedMediaTypes>
   <SupportedMediaTypes>Audio,Photo,Video</SupportedMediaTypes>
@@ -35,7 +34,10 @@
   <RequiresPlainVideoItems>false</RequiresPlainVideoItems>
   <RequiresPlainVideoItems>false</RequiresPlainVideoItems>
   <RequiresPlainFolders>false</RequiresPlainFolders>
   <RequiresPlainFolders>false</RequiresPlainFolders>
   <EnableMSMediaReceiverRegistrar>false</EnableMSMediaReceiverRegistrar>
   <EnableMSMediaReceiverRegistrar>false</EnableMSMediaReceiverRegistrar>
-  <XmlRootAttributes />
+  <XmlRootAttributes>
+    <XmlAttribute name="xmlns" value="urn:schemas-upnp-org:device-1-0" />
+    <XmlAttribute name="xmlns:dlna" value="urn:schemas-dlna-org:device-1-0" />
+  </XmlRootAttributes>
   <DirectPlayProfiles>
   <DirectPlayProfiles>
     <DirectPlayProfile container="avi" audioCodec="mp2,mp3" videoCodec="mpeg4" type="Video" />
     <DirectPlayProfile container="avi" audioCodec="mp2,mp3" videoCodec="mpeg4" type="Video" />
     <DirectPlayProfile container="ts" audioCodec="ac3,mp2,mp3,aac" videoCodec="mpeg1video,mpeg2video,h264" type="Video" />
     <DirectPlayProfile container="ts" audioCodec="ac3,mp2,mp3,aac" videoCodec="mpeg1video,mpeg2video,h264" type="Video" />

Những thai đổi đã bị hủy bỏ vì nó quá lớn
+ 29 - 0
MediaBrowser.Dlna/Profiles/Xml/Vlc.xml


+ 4 - 2
MediaBrowser.Dlna/Profiles/Xml/WDTV Live.xml

@@ -15,7 +15,6 @@
   <ModelDescription>Emby</ModelDescription>
   <ModelDescription>Emby</ModelDescription>
   <ModelNumber>Emby</ModelNumber>
   <ModelNumber>Emby</ModelNumber>
   <ModelUrl>http://emby.media/</ModelUrl>
   <ModelUrl>http://emby.media/</ModelUrl>
-  <IgnoreTranscodeByteRangeRequests>true</IgnoreTranscodeByteRangeRequests>
   <EnableAlbumArtInDidl>false</EnableAlbumArtInDidl>
   <EnableAlbumArtInDidl>false</EnableAlbumArtInDidl>
   <EnableSingleAlbumArtLimit>false</EnableSingleAlbumArtLimit>
   <EnableSingleAlbumArtLimit>false</EnableSingleAlbumArtLimit>
   <SupportedMediaTypes>Audio,Photo,Video</SupportedMediaTypes>
   <SupportedMediaTypes>Audio,Photo,Video</SupportedMediaTypes>
@@ -34,7 +33,10 @@
   <RequiresPlainVideoItems>false</RequiresPlainVideoItems>
   <RequiresPlainVideoItems>false</RequiresPlainVideoItems>
   <RequiresPlainFolders>false</RequiresPlainFolders>
   <RequiresPlainFolders>false</RequiresPlainFolders>
   <EnableMSMediaReceiverRegistrar>false</EnableMSMediaReceiverRegistrar>
   <EnableMSMediaReceiverRegistrar>false</EnableMSMediaReceiverRegistrar>
-  <XmlRootAttributes />
+  <XmlRootAttributes>
+    <XmlAttribute name="xmlns" value="urn:schemas-upnp-org:device-1-0" />
+    <XmlAttribute name="xmlns:dlna" value="urn:schemas-dlna-org:device-1-0" />
+  </XmlRootAttributes>
   <DirectPlayProfiles>
   <DirectPlayProfiles>
     <DirectPlayProfile container="avi" audioCodec="ac3,dca,mp2,mp3,pcm" videoCodec="mpeg1video,mpeg2video,mpeg4,h264,vc1" type="Video" />
     <DirectPlayProfile container="avi" audioCodec="ac3,dca,mp2,mp3,pcm" videoCodec="mpeg1video,mpeg2video,mpeg4,h264,vc1" type="Video" />
     <DirectPlayProfile container="mpeg" audioCodec="ac3,dca,mp2,mp3,pcm" videoCodec="mpeg1video,mpeg2video" type="Video" />
     <DirectPlayProfile container="mpeg" audioCodec="ac3,dca,mp2,mp3,pcm" videoCodec="mpeg1video,mpeg2video" type="Video" />

+ 6 - 6
MediaBrowser.Dlna/Profiles/Xml/Xbox 360.xml

@@ -8,14 +8,12 @@
       <HttpHeaderInfo name="User-Agent" value="Xenon" match="Substring" />
       <HttpHeaderInfo name="User-Agent" value="Xenon" match="Substring" />
     </Headers>
     </Headers>
   </Identification>
   </Identification>
-  <FriendlyName>${HostName} : 1</FriendlyName>
+  <FriendlyName>${HostName}: Emby:</FriendlyName>
   <Manufacturer>Microsoft Corporation</Manufacturer>
   <Manufacturer>Microsoft Corporation</Manufacturer>
-  <ManufacturerUrl>http://www.microsoft.com/</ManufacturerUrl>
+  <ManufacturerUrl>http://www.microsoft.com</ManufacturerUrl>
   <ModelName>Windows Media Player Sharing</ModelName>
   <ModelName>Windows Media Player Sharing</ModelName>
-  <ModelDescription>Emby</ModelDescription>
   <ModelNumber>12.0</ModelNumber>
   <ModelNumber>12.0</ModelNumber>
-  <ModelUrl>http://www.microsoft.com/</ModelUrl>
-  <IgnoreTranscodeByteRangeRequests>false</IgnoreTranscodeByteRangeRequests>
+  <ModelUrl>http://go.microsoft.com/fwlink/?LinkId=105926</ModelUrl>
   <EnableAlbumArtInDidl>false</EnableAlbumArtInDidl>
   <EnableAlbumArtInDidl>false</EnableAlbumArtInDidl>
   <EnableSingleAlbumArtLimit>false</EnableSingleAlbumArtLimit>
   <EnableSingleAlbumArtLimit>false</EnableSingleAlbumArtLimit>
   <SupportedMediaTypes>Audio,Photo,Video</SupportedMediaTypes>
   <SupportedMediaTypes>Audio,Photo,Video</SupportedMediaTypes>
@@ -34,7 +32,9 @@
   <RequiresPlainVideoItems>true</RequiresPlainVideoItems>
   <RequiresPlainVideoItems>true</RequiresPlainVideoItems>
   <RequiresPlainFolders>true</RequiresPlainFolders>
   <RequiresPlainFolders>true</RequiresPlainFolders>
   <EnableMSMediaReceiverRegistrar>true</EnableMSMediaReceiverRegistrar>
   <EnableMSMediaReceiverRegistrar>true</EnableMSMediaReceiverRegistrar>
-  <XmlRootAttributes />
+  <XmlRootAttributes>
+    <XmlAttribute name="xmlns" value="urn:schemas-upnp-org:device-1-0" />
+  </XmlRootAttributes>
   <DirectPlayProfiles>
   <DirectPlayProfiles>
     <DirectPlayProfile container="avi" audioCodec="ac3,mp3" videoCodec="mpeg4" type="Video" />
     <DirectPlayProfile container="avi" audioCodec="ac3,mp3" videoCodec="mpeg4" type="Video" />
     <DirectPlayProfile container="avi" audioCodec="aac" videoCodec="h264" type="Video" />
     <DirectPlayProfile container="avi" audioCodec="aac" videoCodec="h264" type="Video" />

+ 5 - 3
MediaBrowser.Dlna/Profiles/Xml/Xbox One.xml

@@ -2,7 +2,7 @@
 <Profile xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
 <Profile xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
   <Name>Xbox One</Name>
   <Name>Xbox One</Name>
   <Identification>
   <Identification>
-    <FriendlyName>XboxOne</FriendlyName>
+    <ModelName>Xbox One</ModelName>
     <Headers>
     <Headers>
       <HttpHeaderInfo name="FriendlyName.DLNA.ORG" value="XboxOne" match="Substring" />
       <HttpHeaderInfo name="FriendlyName.DLNA.ORG" value="XboxOne" match="Substring" />
       <HttpHeaderInfo name="User-Agent" value="NSPlayer/12" match="Substring" />
       <HttpHeaderInfo name="User-Agent" value="NSPlayer/12" match="Substring" />
@@ -15,7 +15,6 @@
   <ModelDescription>Emby</ModelDescription>
   <ModelDescription>Emby</ModelDescription>
   <ModelNumber>Emby</ModelNumber>
   <ModelNumber>Emby</ModelNumber>
   <ModelUrl>http://emby.media/</ModelUrl>
   <ModelUrl>http://emby.media/</ModelUrl>
-  <IgnoreTranscodeByteRangeRequests>false</IgnoreTranscodeByteRangeRequests>
   <EnableAlbumArtInDidl>false</EnableAlbumArtInDidl>
   <EnableAlbumArtInDidl>false</EnableAlbumArtInDidl>
   <EnableSingleAlbumArtLimit>false</EnableSingleAlbumArtLimit>
   <EnableSingleAlbumArtLimit>false</EnableSingleAlbumArtLimit>
   <SupportedMediaTypes>Audio,Photo,Video</SupportedMediaTypes>
   <SupportedMediaTypes>Audio,Photo,Video</SupportedMediaTypes>
@@ -34,7 +33,10 @@
   <RequiresPlainVideoItems>false</RequiresPlainVideoItems>
   <RequiresPlainVideoItems>false</RequiresPlainVideoItems>
   <RequiresPlainFolders>false</RequiresPlainFolders>
   <RequiresPlainFolders>false</RequiresPlainFolders>
   <EnableMSMediaReceiverRegistrar>false</EnableMSMediaReceiverRegistrar>
   <EnableMSMediaReceiverRegistrar>false</EnableMSMediaReceiverRegistrar>
-  <XmlRootAttributes />
+  <XmlRootAttributes>
+    <XmlAttribute name="xmlns" value="urn:schemas-upnp-org:device-1-0" />
+    <XmlAttribute name="xmlns:dlna" value="urn:schemas-dlna-org:device-1-0" />
+  </XmlRootAttributes>
   <DirectPlayProfiles>
   <DirectPlayProfiles>
     <DirectPlayProfile container="ts" audioCodec="ac3" videoCodec="h264" type="Video" />
     <DirectPlayProfile container="ts" audioCodec="ac3" videoCodec="h264" type="Video" />
     <DirectPlayProfile container="avi" audioCodec="ac3,mp3" videoCodec="mpeg4" type="Video" />
     <DirectPlayProfile container="avi" audioCodec="ac3,mp3" videoCodec="mpeg4" type="Video" />

+ 4 - 2
MediaBrowser.Dlna/Profiles/Xml/foobar2000.xml

@@ -14,7 +14,6 @@
   <ModelDescription>Emby</ModelDescription>
   <ModelDescription>Emby</ModelDescription>
   <ModelNumber>Emby</ModelNumber>
   <ModelNumber>Emby</ModelNumber>
   <ModelUrl>http://emby.media/</ModelUrl>
   <ModelUrl>http://emby.media/</ModelUrl>
-  <IgnoreTranscodeByteRangeRequests>false</IgnoreTranscodeByteRangeRequests>
   <EnableAlbumArtInDidl>false</EnableAlbumArtInDidl>
   <EnableAlbumArtInDidl>false</EnableAlbumArtInDidl>
   <EnableSingleAlbumArtLimit>false</EnableSingleAlbumArtLimit>
   <EnableSingleAlbumArtLimit>false</EnableSingleAlbumArtLimit>
   <SupportedMediaTypes>Audio</SupportedMediaTypes>
   <SupportedMediaTypes>Audio</SupportedMediaTypes>
@@ -33,7 +32,10 @@
   <RequiresPlainVideoItems>false</RequiresPlainVideoItems>
   <RequiresPlainVideoItems>false</RequiresPlainVideoItems>
   <RequiresPlainFolders>false</RequiresPlainFolders>
   <RequiresPlainFolders>false</RequiresPlainFolders>
   <EnableMSMediaReceiverRegistrar>false</EnableMSMediaReceiverRegistrar>
   <EnableMSMediaReceiverRegistrar>false</EnableMSMediaReceiverRegistrar>
-  <XmlRootAttributes />
+  <XmlRootAttributes>
+    <XmlAttribute name="xmlns" value="urn:schemas-upnp-org:device-1-0" />
+    <XmlAttribute name="xmlns:dlna" value="urn:schemas-dlna-org:device-1-0" />
+  </XmlRootAttributes>
   <DirectPlayProfiles>
   <DirectPlayProfiles>
     <DirectPlayProfile container="mp3" audioCodec="mp2,mp3" type="Audio" />
     <DirectPlayProfile container="mp3" audioCodec="mp2,mp3" type="Audio" />
     <DirectPlayProfile container="mp4" audioCodec="mp4" type="Audio" />
     <DirectPlayProfile container="mp4" audioCodec="mp4" type="Audio" />

+ 26 - 7
MediaBrowser.Dlna/Server/DescriptionXmlBuilder.cs

@@ -18,8 +18,9 @@ namespace MediaBrowser.Dlna.Server
         private readonly string _serverUdn;
         private readonly string _serverUdn;
         private readonly string _serverAddress;
         private readonly string _serverAddress;
         private readonly string _serverName;
         private readonly string _serverName;
+        private readonly string _serverId;
 
 
-        public DescriptionXmlBuilder(DeviceProfile profile, string serverUdn, string serverAddress, string serverName)
+        public DescriptionXmlBuilder(DeviceProfile profile, string serverUdn, string serverAddress, string serverName, string serverId)
         {
         {
             if (string.IsNullOrWhiteSpace(serverUdn))
             if (string.IsNullOrWhiteSpace(serverUdn))
             {
             {
@@ -35,6 +36,7 @@ namespace MediaBrowser.Dlna.Server
             _serverUdn = serverUdn;
             _serverUdn = serverUdn;
             _serverAddress = serverAddress;
             _serverAddress = serverAddress;
             _serverName = serverName;
             _serverName = serverName;
+            _serverId = serverId;
         }
         }
 
 
         private bool EnableAbsoluteUrls
         private bool EnableAbsoluteUrls
@@ -48,7 +50,7 @@ namespace MediaBrowser.Dlna.Server
 
 
             builder.Append("<?xml version=\"1.0\"?>");
             builder.Append("<?xml version=\"1.0\"?>");
 
 
-            builder.Append("<root xmlns=\"urn:schemas-upnp-org:device-1-0\" xmlns:dlna=\"urn:schemas-dlna-org:device-1-0\"");
+            builder.Append("<root");
             foreach (var att in _profile.XmlRootAttributes)
             foreach (var att in _profile.XmlRootAttributes)
             {
             {
                 builder.AppendFormat(" {0}=\"{1}\"", att.Name, att.Value);
                 builder.AppendFormat(" {0}=\"{1}\"", att.Name, att.Value);
@@ -72,7 +74,7 @@ namespace MediaBrowser.Dlna.Server
             builder.Append("<device>");
             builder.Append("<device>");
             AppendDeviceProperties(builder);
             AppendDeviceProperties(builder);
 
 
-            AppendIconList(builder);
+            //AppendIconList(builder);
             AppendServiceList(builder);
             AppendServiceList(builder);
             builder.Append("</device>");
             builder.Append("</device>");
         }
         }
@@ -80,20 +82,37 @@ namespace MediaBrowser.Dlna.Server
         private void AppendDeviceProperties(StringBuilder builder)
         private void AppendDeviceProperties(StringBuilder builder)
         {
         {
             builder.Append("<UDN>uuid:" + SecurityElement.Escape(_serverUdn) + "</UDN>");
             builder.Append("<UDN>uuid:" + SecurityElement.Escape(_serverUdn) + "</UDN>");
-            builder.Append("<dlna:X_DLNACAP>" + SecurityElement.Escape(_profile.XDlnaCap ?? string.Empty) + "</dlna:X_DLNACAP>");
+
+            if (!string.IsNullOrWhiteSpace(_profile.XDlnaCap))
+            {
+                builder.Append("<dlna:X_DLNACAP>" + SecurityElement.Escape(_profile.XDlnaCap ?? string.Empty) + "</dlna:X_DLNACAP>");
+            }
 
 
             builder.Append("<dlna:X_DLNADOC xmlns:dlna=\"urn:schemas-dlna-org:device-1-0\">M-DMS-1.50</dlna:X_DLNADOC>");
             builder.Append("<dlna:X_DLNADOC xmlns:dlna=\"urn:schemas-dlna-org:device-1-0\">M-DMS-1.50</dlna:X_DLNADOC>");
             builder.Append("<dlna:X_DLNADOC xmlns:dlna=\"urn:schemas-dlna-org:device-1-0\">" + SecurityElement.Escape(_profile.XDlnaDoc ?? string.Empty) + "</dlna:X_DLNADOC>");
             builder.Append("<dlna:X_DLNADOC xmlns:dlna=\"urn:schemas-dlna-org:device-1-0\">" + SecurityElement.Escape(_profile.XDlnaDoc ?? string.Empty) + "</dlna:X_DLNADOC>");
-
+            
             builder.Append("<friendlyName>" + SecurityElement.Escape(GetFriendlyName()) + "</friendlyName>");
             builder.Append("<friendlyName>" + SecurityElement.Escape(GetFriendlyName()) + "</friendlyName>");
             builder.Append("<deviceType>urn:schemas-upnp-org:device:MediaServer:1</deviceType>");
             builder.Append("<deviceType>urn:schemas-upnp-org:device:MediaServer:1</deviceType>");
             builder.Append("<manufacturer>" + SecurityElement.Escape(_profile.Manufacturer ?? string.Empty) + "</manufacturer>");
             builder.Append("<manufacturer>" + SecurityElement.Escape(_profile.Manufacturer ?? string.Empty) + "</manufacturer>");
             builder.Append("<manufacturerURL>" + SecurityElement.Escape(_profile.ManufacturerUrl ?? string.Empty) + "</manufacturerURL>");
             builder.Append("<manufacturerURL>" + SecurityElement.Escape(_profile.ManufacturerUrl ?? string.Empty) + "</manufacturerURL>");
             builder.Append("<modelName>" + SecurityElement.Escape(_profile.ModelName ?? string.Empty) + "</modelName>");
             builder.Append("<modelName>" + SecurityElement.Escape(_profile.ModelName ?? string.Empty) + "</modelName>");
-            builder.Append("<modelDescription>" + SecurityElement.Escape(_profile.ModelDescription ?? string.Empty) + "</modelDescription>");
+
+            if (!string.IsNullOrWhiteSpace(_profile.ModelDescription))
+            {
+                builder.Append("<modelDescription>" + SecurityElement.Escape(_profile.ModelDescription ?? string.Empty) + "</modelDescription>");
+            }
+            
             builder.Append("<modelNumber>" + SecurityElement.Escape(_profile.ModelNumber ?? string.Empty) + "</modelNumber>");
             builder.Append("<modelNumber>" + SecurityElement.Escape(_profile.ModelNumber ?? string.Empty) + "</modelNumber>");
             builder.Append("<modelURL>" + SecurityElement.Escape(_profile.ModelUrl ?? string.Empty) + "</modelURL>");
             builder.Append("<modelURL>" + SecurityElement.Escape(_profile.ModelUrl ?? string.Empty) + "</modelURL>");
-            builder.Append("<serialNumber>" + SecurityElement.Escape(_profile.SerialNumber ?? string.Empty) + "</serialNumber>");
+
+            if (string.IsNullOrWhiteSpace(_profile.SerialNumber))
+            {
+                builder.Append("<serialNumber>" + SecurityElement.Escape(_serverId) + "</serialNumber>");
+            }
+            else
+            {
+                builder.Append("<serialNumber>" + SecurityElement.Escape(_profile.SerialNumber) + "</serialNumber>");
+            }
 
 
             builder.Append("<presentationURL>" + SecurityElement.Escape(_serverAddress) + "</presentationURL>");
             builder.Append("<presentationURL>" + SecurityElement.Escape(_serverAddress) + "</presentationURL>");
 
 

+ 4 - 2
MediaBrowser.Dlna/Service/BaseControlHandler.cs

@@ -27,14 +27,16 @@ namespace MediaBrowser.Dlna.Service
         {
         {
             try
             try
             {
             {
-                if (Config.GetDlnaConfiguration().EnableDebugLogging)
+                var enableDebugLogging = Config.GetDlnaConfiguration().EnableDebugLogging;
+
+                if (enableDebugLogging)
                 {
                 {
                     LogRequest(request);
                     LogRequest(request);
                 }
                 }
 
 
                 var response = ProcessControlRequestInternal(request);
                 var response = ProcessControlRequestInternal(request);
 
 
-                if (Config.GetDlnaConfiguration().EnableDebugLogging)
+                if (enableDebugLogging)
                 {
                 {
                     LogResponse(response);
                     LogResponse(response);
                 }
                 }

+ 57 - 21
MediaBrowser.Dlna/Ssdp/Datagram.cs

@@ -12,13 +12,15 @@ namespace MediaBrowser.Dlna.Ssdp
         public EndPoint FromEndPoint { get; private set; }
         public EndPoint FromEndPoint { get; private set; }
         public string Message { get; private set; }
         public string Message { get; private set; }
         public bool IgnoreBindFailure { get; private set; }
         public bool IgnoreBindFailure { get; private set; }
+        public bool EnableDebugLogging { get; private set; }
 
 
         private readonly ILogger _logger;
         private readonly ILogger _logger;
 
 
-        public Datagram(EndPoint toEndPoint, EndPoint fromEndPoint, ILogger logger, string message, bool ignoreBindFailure)
+        public Datagram(EndPoint toEndPoint, EndPoint fromEndPoint, ILogger logger, string message, bool ignoreBindFailure, bool enableDebugLogging)
         {
         {
             Message = message;
             Message = message;
             _logger = logger;
             _logger = logger;
+            EnableDebugLogging = enableDebugLogging;
             IgnoreBindFailure = ignoreBindFailure;
             IgnoreBindFailure = ignoreBindFailure;
             FromEndPoint = fromEndPoint;
             FromEndPoint = fromEndPoint;
             ToEndPoint = toEndPoint;
             ToEndPoint = toEndPoint;
@@ -27,59 +29,93 @@ namespace MediaBrowser.Dlna.Ssdp
         public void Send()
         public void Send()
         {
         {
             var msg = Encoding.ASCII.GetBytes(Message);
             var msg = Encoding.ASCII.GetBytes(Message);
-            try
+
+            var socket = CreateSocket();
+
+            if (socket == null)
             {
             {
-                var client = CreateSocket();
+                return;
+            }
 
 
-                if (FromEndPoint != null)
+            if (FromEndPoint != null)
+            {
+                try
                 {
                 {
-                    try
+                    socket.Bind(FromEndPoint);
+                }
+                catch (Exception ex)
+                {
+                    if (EnableDebugLogging)
                     {
                     {
-                        client.Bind(FromEndPoint);
+                        _logger.ErrorException("Error binding datagram socket", ex);
                     }
                     }
-                    catch
+
+                    if (!IgnoreBindFailure)
                     {
                     {
-                        if (!IgnoreBindFailure) throw;
+                        CloseSocket(socket, false);
+
+                        return;
                     }
                     }
                 }
                 }
+            }
 
 
-                client.BeginSendTo(msg, 0, msg.Length, SocketFlags.None, ToEndPoint, result =>
+            try
+            {
+                socket.BeginSendTo(msg, 0, msg.Length, SocketFlags.None, ToEndPoint, result =>
                 {
                 {
                     try
                     try
                     {
                     {
-                        client.EndSend(result);
+                        socket.EndSend(result);
                     }
                     }
                     catch (Exception ex)
                     catch (Exception ex)
                     {
                     {
-                        if (!IgnoreBindFailure)
+                        if (!IgnoreBindFailure || EnableDebugLogging)
                         {
                         {
                             _logger.ErrorException("Error sending Datagram to {0} from {1}: " + Message, ex, ToEndPoint, FromEndPoint == null ? "" : FromEndPoint.ToString());
                             _logger.ErrorException("Error sending Datagram to {0} from {1}: " + Message, ex, ToEndPoint, FromEndPoint == null ? "" : FromEndPoint.ToString());
                         }
                         }
                     }
                     }
                     finally
                     finally
                     {
                     {
-                        try
-                        {
-                            client.Close();
-                        }
-                        catch (Exception)
-                        {
-                        }
+                        CloseSocket(socket, true);
                     }
                     }
                 }, null);
                 }, null);
             }
             }
             catch (Exception ex)
             catch (Exception ex)
             {
             {
                 _logger.ErrorException("Error sending Datagram to {0} from {1}: " + Message, ex, ToEndPoint, FromEndPoint == null ? "" : FromEndPoint.ToString());
                 _logger.ErrorException("Error sending Datagram to {0} from {1}: " + Message, ex, ToEndPoint, FromEndPoint == null ? "" : FromEndPoint.ToString());
+                CloseSocket(socket, false);
+            }
+        }
+
+        private void CloseSocket(Socket socket, bool logError)
+        {
+            try
+            {
+                socket.Close();
+            }
+            catch (Exception ex)
+            {
+                if (logError && EnableDebugLogging)
+                {
+                    _logger.ErrorException("Error closing datagram socket", ex);
+                }
             }
             }
         }
         }
 
 
         private Socket CreateSocket()
         private Socket CreateSocket()
         {
         {
-            var socket = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp);
+            try
+            {
+                var socket = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp);
 
 
-            socket.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, true);
-            return socket;
+                socket.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, true);
+                return socket;
+            }
+            catch (Exception ex)
+            {
+                _logger.ErrorException("Error creating socket", ex);
+                return null;
+            }
         }
         }
     }
     }
 }
 }

+ 18 - 9
MediaBrowser.Dlna/Ssdp/DeviceDiscovery.cs

@@ -1,7 +1,7 @@
 using MediaBrowser.Common.Events;
 using MediaBrowser.Common.Events;
-using MediaBrowser.Common.Net;
 using MediaBrowser.Controller;
 using MediaBrowser.Controller;
 using MediaBrowser.Controller.Configuration;
 using MediaBrowser.Controller.Configuration;
+using MediaBrowser.Controller.Dlna;
 using MediaBrowser.Model.Logging;
 using MediaBrowser.Model.Logging;
 using System;
 using System;
 using System.Collections.Generic;
 using System.Collections.Generic;
@@ -142,7 +142,10 @@ namespace MediaBrowser.Dlna.Ssdp
                             args.EndPoint = endPoint;
                             args.EndPoint = endPoint;
                             args.LocalIp = localIp;
                             args.LocalIp = localIp;
 
 
-                            TryCreateDevice(args);
+                            if (!_ssdpHandler.IsSelfNotification(args))
+                            {
+                                TryCreateDevice(args);
+                            }
                         }
                         }
                     }
                     }
 
 
@@ -183,7 +186,6 @@ namespace MediaBrowser.Dlna.Ssdp
                 }
                 }
 
 
             }, _tokenSource.Token, TaskCreationOptions.LongRunning);
             }, _tokenSource.Token, TaskCreationOptions.LongRunning);
-
         }
         }
 
 
         private Socket GetMulticastSocket(IPAddress localIpAddress, EndPoint localEndpoint)
         private Socket GetMulticastSocket(IPAddress localIpAddress, EndPoint localEndpoint)
@@ -203,18 +205,25 @@ namespace MediaBrowser.Dlna.Ssdp
             string nts;
             string nts;
             args.Headers.TryGetValue("NTS", out nts);
             args.Headers.TryGetValue("NTS", out nts);
 
 
+            if (String.Equals(nts, "ssdp:byebye", StringComparison.OrdinalIgnoreCase))
+            {
+                if (String.Equals(args.Method, "NOTIFY", StringComparison.OrdinalIgnoreCase))
+                {
+                    if (!_disposed)
+                    {
+                        EventHelper.FireEventIfNotNull(DeviceLeft, this, args, _logger);
+                    }
+                }
+
+                return;
+            }
+
             string usn;
             string usn;
             if (!args.Headers.TryGetValue("USN", out usn)) usn = string.Empty;
             if (!args.Headers.TryGetValue("USN", out usn)) usn = string.Empty;
 
 
             string nt;
             string nt;
             if (!args.Headers.TryGetValue("NT", out nt)) nt = string.Empty;
             if (!args.Headers.TryGetValue("NT", out nt)) nt = string.Empty;
 
 
-            // Ignore when a device is indicating it's shutting down
-            if (string.Equals(nts, "ssdp:byebye", StringComparison.OrdinalIgnoreCase))
-            {
-                return;
-            }
-
             // Need to be able to download device description
             // Need to be able to download device description
             string location;
             string location;
             if (!args.Headers.TryGetValue("Location", out location) ||
             if (!args.Headers.TryGetValue("Location", out location) ||

+ 114 - 30
MediaBrowser.Dlna/Ssdp/SsdpHandler.cs

@@ -1,6 +1,8 @@
-using MediaBrowser.Common.Configuration;
+using MediaBrowser.Common;
+using MediaBrowser.Common.Configuration;
 using MediaBrowser.Common.Events;
 using MediaBrowser.Common.Events;
 using MediaBrowser.Controller.Configuration;
 using MediaBrowser.Controller.Configuration;
+using MediaBrowser.Controller.Dlna;
 using MediaBrowser.Dlna.Server;
 using MediaBrowser.Dlna.Server;
 using MediaBrowser.Model.Logging;
 using MediaBrowser.Model.Logging;
 using System;
 using System;
@@ -16,7 +18,7 @@ using System.Threading.Tasks;
 
 
 namespace MediaBrowser.Dlna.Ssdp
 namespace MediaBrowser.Dlna.Ssdp
 {
 {
-    public class SsdpHandler : IDisposable
+    public class SsdpHandler : IDisposable, ISsdpHandler
     {
     {
         private Socket _socket;
         private Socket _socket;
 
 
@@ -39,13 +41,39 @@ namespace MediaBrowser.Dlna.Ssdp
         private bool _isDisposed;
         private bool _isDisposed;
         private readonly ConcurrentDictionary<Guid, List<UpnpDevice>> _devices = new ConcurrentDictionary<Guid, List<UpnpDevice>>();
         private readonly ConcurrentDictionary<Guid, List<UpnpDevice>> _devices = new ConcurrentDictionary<Guid, List<UpnpDevice>>();
 
 
-        public SsdpHandler(ILogger logger, IServerConfigurationManager config, string serverSignature)
+        private readonly IApplicationHost _appHost;
+
+        public SsdpHandler(ILogger logger, IServerConfigurationManager config, IApplicationHost appHost)
         {
         {
             _logger = logger;
             _logger = logger;
             _config = config;
             _config = config;
-            _serverSignature = serverSignature;
+            _appHost = appHost;
 
 
             _config.NamedConfigurationUpdated += _config_ConfigurationUpdated;
             _config.NamedConfigurationUpdated += _config_ConfigurationUpdated;
+            _serverSignature = GenerateServerSignature();
+        }
+
+        private string GenerateServerSignature()
+        {
+            var os = Environment.OSVersion;
+            var pstring = os.Platform.ToString();
+            switch (os.Platform)
+            {
+                case PlatformID.Win32NT:
+                case PlatformID.Win32S:
+                case PlatformID.Win32Windows:
+                    pstring = "WIN";
+                    break;
+            }
+
+            return String.Format(
+              "{0}{1}/{2}.{3} UPnP/1.0 DLNADOC/1.5 Emby/{4}",
+              pstring,
+              IntPtr.Size * 8,
+              os.Version.Major,
+              os.Version.Minor,
+              _appHost.ApplicationVersion
+              );
         }
         }
 
 
         void _config_ConfigurationUpdated(object sender, ConfigurationUpdateEventArgs e)
         void _config_ConfigurationUpdated(object sender, ConfigurationUpdateEventArgs e)
@@ -60,24 +88,21 @@ namespace MediaBrowser.Dlna.Ssdp
 
 
         private async void OnMessageReceived(SsdpMessageEventArgs args)
         private async void OnMessageReceived(SsdpMessageEventArgs args)
         {
         {
-            if (string.Equals(args.Method, "M-SEARCH", StringComparison.OrdinalIgnoreCase))
-            {
-                var headers = args.Headers;
+            var headers = args.Headers;
+            string st;
 
 
+            if (string.Equals(args.Method, "M-SEARCH", StringComparison.OrdinalIgnoreCase) && headers.TryGetValue("st", out st))
+            {
                 TimeSpan delay = GetSearchDelay(headers);
                 TimeSpan delay = GetSearchDelay(headers);
-                
+
                 if (_config.GetDlnaConfiguration().EnableDebugLogging)
                 if (_config.GetDlnaConfiguration().EnableDebugLogging)
                 {
                 {
                     _logger.Debug("Delaying search response by {0} seconds", delay.TotalSeconds);
                     _logger.Debug("Delaying search response by {0} seconds", delay.TotalSeconds);
                 }
                 }
-                
+
                 await Task.Delay(delay).ConfigureAwait(false);
                 await Task.Delay(delay).ConfigureAwait(false);
 
 
-                string st;
-                if (headers.TryGetValue("st", out st))
-                {
-                    RespondToSearch(args.EndPoint, st);
-                }
+                RespondToSearch(args.EndPoint, st);
             }
             }
 
 
             EventHelper.FireEventIfNotNull(MessageReceived, this, args, _logger);
             EventHelper.FireEventIfNotNull(MessageReceived, this, args, _logger);
@@ -117,7 +142,7 @@ namespace MediaBrowser.Dlna.Ssdp
             values["MX"] = "3";
             values["MX"] = "3";
 
 
             // UDP is unreliable, so send 3 requests at a time (per Upnp spec, sec 1.1.2)
             // UDP is unreliable, so send 3 requests at a time (per Upnp spec, sec 1.1.2)
-            SendDatagram("M-SEARCH * HTTP/1.1", values, localIp, 1);
+            SendDatagram("M-SEARCH * HTTP/1.1", values, localIp, 2);
         }
         }
 
 
         public void SendDatagram(string header,
         public void SendDatagram(string header,
@@ -138,9 +163,11 @@ namespace MediaBrowser.Dlna.Ssdp
             var msg = new SsdpMessageBuilder().BuildMessage(header, values);
             var msg = new SsdpMessageBuilder().BuildMessage(header, values);
             var queued = false;
             var queued = false;
 
 
+            var enableDebugLogging = _config.GetDlnaConfiguration().EnableDebugLogging;
+
             for (var i = 0; i < sendCount; i++)
             for (var i = 0; i < sendCount; i++)
             {
             {
-                var dgram = new Datagram(endpoint, localAddress, _logger, msg, ignoreBindFailure);
+                var dgram = new Datagram(endpoint, localAddress, _logger, msg, ignoreBindFailure, enableDebugLogging);
 
 
                 if (_messageQueue.Count == 0)
                 if (_messageQueue.Count == 0)
                 {
                 {
@@ -184,10 +211,9 @@ namespace MediaBrowser.Dlna.Ssdp
 
 
         private void RespondToSearch(EndPoint endpoint, string deviceType)
         private void RespondToSearch(EndPoint endpoint, string deviceType)
         {
         {
-            if (_config.GetDlnaConfiguration().EnableDebugLogging)
-            {
-                _logger.Debug("RespondToSearch");
-            }
+            var enableDebugLogging = _config.GetDlnaConfiguration().EnableDebugLogging;
+
+            var isLogged = false;
 
 
             const string header = "HTTP/1.1 200 OK";
             const string header = "HTTP/1.1 200 OK";
 
 
@@ -196,6 +222,15 @@ namespace MediaBrowser.Dlna.Ssdp
                 if (string.Equals(deviceType, "ssdp:all", StringComparison.OrdinalIgnoreCase) ||
                 if (string.Equals(deviceType, "ssdp:all", StringComparison.OrdinalIgnoreCase) ||
                     string.Equals(deviceType, d.Type, StringComparison.OrdinalIgnoreCase))
                     string.Equals(deviceType, d.Type, StringComparison.OrdinalIgnoreCase))
                 {
                 {
+                    if (!isLogged)
+                    {
+                        if (enableDebugLogging)
+                        {
+                            _logger.Debug("Responding to search from {0} for {1}", endpoint, deviceType);
+                        }
+                        isLogged = true;
+                    }
+
                     var values = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);
                     var values = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);
 
 
                     values["CACHE-CONTROL"] = "max-age = 600";
                     values["CACHE-CONTROL"] = "max-age = 600";
@@ -210,7 +245,7 @@ namespace MediaBrowser.Dlna.Ssdp
                     SendDatagram(header, values, endpoint, new IPEndPoint(d.Address, 0), true, 1);
                     SendDatagram(header, values, endpoint, new IPEndPoint(d.Address, 0), true, 1);
                     //SendDatagram(header, values, endpoint, null, true);
                     //SendDatagram(header, values, endpoint, null, true);
 
 
-                    if (_config.GetDlnaConfiguration().EnableDebugLogging)
+                    if (enableDebugLogging)
                     {
                     {
                         _logger.Debug("{1} - Responded to a {0} request to {2}", d.Type, endpoint, d.Address.ToString());
                         _logger.Debug("{1} - Responded to a {0} request to {2}", d.Type, endpoint, d.Address.ToString());
                     }
                     }
@@ -288,7 +323,9 @@ namespace MediaBrowser.Dlna.Ssdp
 
 
                 var received = (byte[])result.AsyncState;
                 var received = (byte[])result.AsyncState;
 
 
-                if (_config.GetDlnaConfiguration().EnableDebugLogging)
+                var enableDebugLogging = _config.GetDlnaConfiguration().EnableDebugLogging;
+
+                if (enableDebugLogging)
                 {
                 {
                     _logger.Debug(Encoding.ASCII.GetString(received));
                     _logger.Debug(Encoding.ASCII.GetString(received));
                 }
                 }
@@ -296,7 +333,12 @@ namespace MediaBrowser.Dlna.Ssdp
                 var args = SsdpHelper.ParseSsdpResponse(received);
                 var args = SsdpHelper.ParseSsdpResponse(received);
                 args.EndPoint = endpoint;
                 args.EndPoint = endpoint;
 
 
-                if (_config.GetDlnaConfiguration().EnableDebugLogging)
+                if (IsSelfNotification(args))
+                {
+                    return;
+                }
+
+                if (enableDebugLogging)
                 {
                 {
                     var headerTexts = args.Headers.Select(i => string.Format("{0}={1}", i.Key, i.Value));
                     var headerTexts = args.Headers.Select(i => string.Format("{0}={1}", i.Key, i.Value));
                     var headerText = string.Join(",", headerTexts.ToArray());
                     var headerText = string.Join(",", headerTexts.ToArray());
@@ -317,6 +359,44 @@ namespace MediaBrowser.Dlna.Ssdp
             }
             }
         }
         }
 
 
+        internal bool IsSelfNotification(SsdpMessageEventArgs args)
+        {
+            // Avoid responding to self search messages
+            //string serverId;
+            //if (args.Headers.TryGetValue("X-EMBYSERVERID", out serverId) &&
+            //    string.Equals(serverId, _appHost.SystemId, StringComparison.OrdinalIgnoreCase))
+            //{
+            //    return true;
+            //}
+
+            string server;
+            args.Headers.TryGetValue("SERVER", out server);
+
+            if (string.Equals(server, _serverSignature, StringComparison.OrdinalIgnoreCase))
+            {
+                return true;
+            }
+            return false;
+            //string usn;
+            //args.Headers.TryGetValue("USN", out usn);
+
+            //if (string.IsNullOrWhiteSpace(usn))
+            //{
+            //    return false;
+            //}
+
+            //_logger.Debug("IsSelfNotification test: " + usn);
+
+            //return RegisteredDevices.Any(i =>
+            //{
+            //    var isSameDevice = string.Equals(usn, i.USN, StringComparison.OrdinalIgnoreCase) ||
+            //           i.USN.IndexOf(usn, StringComparison.OrdinalIgnoreCase) != 1 ||
+            //           usn.IndexOf(i.USN, StringComparison.OrdinalIgnoreCase) != 1;
+
+            //    return isSameDevice;
+            //});
+        }
+
         public void Dispose()
         public void Dispose()
         {
         {
             _config.NamedConfigurationUpdated -= _config_ConfigurationUpdated;
             _config.NamedConfigurationUpdated -= _config_ConfigurationUpdated;
@@ -371,17 +451,19 @@ namespace MediaBrowser.Dlna.Ssdp
 
 
         private void NotifyAll()
         private void NotifyAll()
         {
         {
-            if (_config.GetDlnaConfiguration().EnableDebugLogging)
+            var enableDebugLogging = _config.GetDlnaConfiguration().EnableDebugLogging;
+
+            if (enableDebugLogging)
             {
             {
                 _logger.Debug("Sending alive notifications");
                 _logger.Debug("Sending alive notifications");
             }
             }
             foreach (var d in RegisteredDevices)
             foreach (var d in RegisteredDevices)
             {
             {
-                NotifyDevice(d, "alive", 1);
+                NotifyDevice(d, "alive", 1, enableDebugLogging);
             }
             }
         }
         }
 
 
-        private void NotifyDevice(UpnpDevice dev, string type, int sendCount)
+        private void NotifyDevice(UpnpDevice dev, string type, int sendCount, bool logMessage)
         {
         {
             const string header = "NOTIFY * HTTP/1.1";
             const string header = "NOTIFY * HTTP/1.1";
 
 
@@ -396,7 +478,7 @@ namespace MediaBrowser.Dlna.Ssdp
             values["NT"] = dev.Type;
             values["NT"] = dev.Type;
             values["USN"] = dev.USN;
             values["USN"] = dev.USN;
 
 
-            if (_config.GetDlnaConfiguration().EnableDebugLogging)
+            if (logMessage)
             {
             {
                 _logger.Debug("{0} said {1}", dev.USN, type);
                 _logger.Debug("{0} said {1}", dev.USN, type);
             }
             }
@@ -429,7 +511,7 @@ namespace MediaBrowser.Dlna.Ssdp
 
 
                 foreach (var d in dl.ToList())
                 foreach (var d in dl.ToList())
                 {
                 {
-                    NotifyDevice(d, "byebye", 2);
+                    NotifyDevice(d, "byebye", 2, true);
                 }
                 }
 
 
                 _logger.Debug("Unregistered mount {0}", uuid);
                 _logger.Debug("Unregistered mount {0}", uuid);
@@ -440,13 +522,15 @@ namespace MediaBrowser.Dlna.Ssdp
         private int _aliveNotifierIntervalMs;
         private int _aliveNotifierIntervalMs;
         private void ReloadAliveNotifier()
         private void ReloadAliveNotifier()
         {
         {
-            if (!_config.GetDlnaConfiguration().BlastAliveMessages)
+            var config = _config.GetDlnaConfiguration();
+
+            if (!config.BlastAliveMessages)
             {
             {
                 DisposeNotificationTimer();
                 DisposeNotificationTimer();
                 return;
                 return;
             }
             }
 
 
-            var intervalMs = _config.GetDlnaConfiguration().BlastAliveMessageIntervalSeconds * 1000;
+            var intervalMs = config.BlastAliveMessageIntervalSeconds * 1000;
 
 
             if (_notificationTimer == null || _aliveNotifierIntervalMs != intervalMs)
             if (_notificationTimer == null || _aliveNotifierIntervalMs != intervalMs)
             {
             {

+ 4 - 2
MediaBrowser.Dlna/Ssdp/SsdpHelper.cs

@@ -1,4 +1,5 @@
-using System;
+using MediaBrowser.Controller.Dlna;
+using System;
 using System.Collections.Generic;
 using System.Collections.Generic;
 using System.IO;
 using System.IO;
 using System.Text;
 using System.Text;
@@ -34,7 +35,8 @@ namespace MediaBrowser.Dlna.Ssdp
                     return new SsdpMessageEventArgs
                     return new SsdpMessageEventArgs
                     {
                     {
                         Method = method,
                         Method = method,
-                        Headers = headers
+                        Headers = headers,
+                        Message = data
                     };
                     };
                 }
                 }
             }
             }

+ 3 - 25
MediaBrowser.MediaEncoding/Encoder/BaseEncoder.cs

@@ -840,7 +840,7 @@ namespace MediaBrowser.MediaEncoding.Encoder
                 var maxWidthParam = request.MaxWidth.Value.ToString(UsCulture);
                 var maxWidthParam = request.MaxWidth.Value.ToString(UsCulture);
                 var maxHeightParam = request.MaxHeight.Value.ToString(UsCulture);
                 var maxHeightParam = request.MaxHeight.Value.ToString(UsCulture);
 
 
-                filters.Add(string.Format("scale=trunc(min(iw\\,{0})/2)*2:trunc(min((iw/dar)\\,{1})/2)*2", maxWidthParam, maxHeightParam));
+                filters.Add(string.Format("scale=trunc(min(max(iw\\,ih*dar)\\,min({0}\\,{1}*dar))/2)*2:trunc(min(max(iw/dar\\,ih)\\,min({0}/dar\\,{1}))/2)*2", maxWidthParam, maxHeightParam));
             }
             }
 
 
             // If a fixed width was requested
             // If a fixed width was requested
@@ -860,7 +860,7 @@ namespace MediaBrowser.MediaEncoding.Encoder
             }
             }
 
 
             // If a max width was requested
             // If a max width was requested
-            else if (request.MaxWidth.HasValue && (!request.MaxHeight.HasValue || state.VideoStream == null))
+            else if (request.MaxWidth.HasValue)
             {
             {
                 var maxWidthParam = request.MaxWidth.Value.ToString(UsCulture);
                 var maxWidthParam = request.MaxWidth.Value.ToString(UsCulture);
 
 
@@ -868,35 +868,13 @@ namespace MediaBrowser.MediaEncoding.Encoder
             }
             }
 
 
             // If a max height was requested
             // If a max height was requested
-            else if (request.MaxHeight.HasValue && (!request.MaxWidth.HasValue || state.VideoStream == null))
+            else if (request.MaxHeight.HasValue)
             {
             {
                 var maxHeightParam = request.MaxHeight.Value.ToString(UsCulture);
                 var maxHeightParam = request.MaxHeight.Value.ToString(UsCulture);
 
 
                 filters.Add(string.Format("scale=trunc(oh*a*2)/2:min(ih\\,{0})", maxHeightParam));
                 filters.Add(string.Format("scale=trunc(oh*a*2)/2:min(ih\\,{0})", maxHeightParam));
             }
             }
 
 
-            else if (request.MaxWidth.HasValue ||
-                request.MaxHeight.HasValue ||
-                request.Width.HasValue ||
-                request.Height.HasValue)
-            {
-                if (state.VideoStream != null)
-                {
-                    // Need to perform calculations manually
-
-                    // Try to account for bad media info
-                    var currentHeight = state.VideoStream.Height ?? request.MaxHeight ?? request.Height ?? 0;
-                    var currentWidth = state.VideoStream.Width ?? request.MaxWidth ?? request.Width ?? 0;
-
-                    var outputSize = DrawingUtils.Resize(currentWidth, currentHeight, request.Width, request.Height, request.MaxWidth, request.MaxHeight);
-
-                    var manualWidthParam = outputSize.Width.ToString(UsCulture);
-                    var manualHeightParam = outputSize.Height.ToString(UsCulture);
-
-                    filters.Add(string.Format("scale=trunc({0}/2)*2:trunc({1}/2)*2", manualWidthParam, manualHeightParam));
-                }
-            }
-
             var output = string.Empty;
             var output = string.Empty;
 
 
             if (state.SubtitleStream != null && state.SubtitleStream.IsTextSubtitleStream)
             if (state.SubtitleStream != null && state.SubtitleStream.IsTextSubtitleStream)

+ 0 - 2
MediaBrowser.MediaEncoding/Encoder/EncodingJobFactory.cs

@@ -716,8 +716,6 @@ namespace MediaBrowser.MediaEncoding.Encoder
                 profile.GetVideoMediaProfile(outputContainer,
                 profile.GetVideoMediaProfile(outputContainer,
                 audioCodec,
                 audioCodec,
                 videoCodec,
                 videoCodec,
-                state.OutputAudioBitrate,
-                state.OutputAudioChannels,
                 state.OutputWidth,
                 state.OutputWidth,
                 state.OutputHeight,
                 state.OutputHeight,
                 state.TargetVideoBitDepth,
                 state.TargetVideoBitDepth,

+ 160 - 136
MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs

@@ -199,82 +199,83 @@ namespace MediaBrowser.MediaEncoding.Encoder
 
 
             await _ffProbeResourcePool.WaitAsync(cancellationToken).ConfigureAwait(false);
             await _ffProbeResourcePool.WaitAsync(cancellationToken).ConfigureAwait(false);
 
 
-            var processWrapper = new ProcessWrapper(process, this);
-
-            try
-            {
-                StartProcess(processWrapper);
-            }
-            catch (Exception ex)
+            using (var processWrapper = new ProcessWrapper(process, this))
             {
             {
-                _ffProbeResourcePool.Release();
+                try
+                {
+                    StartProcess(processWrapper);
+                }
+                catch (Exception ex)
+                {
+                    _ffProbeResourcePool.Release();
 
 
-                _logger.ErrorException("Error starting ffprobe", ex);
+                    _logger.ErrorException("Error starting ffprobe", ex);
 
 
-                throw;
-            }
+                    throw;
+                }
 
 
-            try
-            {
-                process.BeginErrorReadLine();
+                try
+                {
+                    process.BeginErrorReadLine();
 
 
-                var result = _jsonSerializer.DeserializeFromStream<InternalMediaInfoResult>(process.StandardOutput.BaseStream);
+                    var result = _jsonSerializer.DeserializeFromStream<InternalMediaInfoResult>(process.StandardOutput.BaseStream);
 
 
-                if (result != null)
-                {
-                    if (result.streams != null)
+                    if (result != null)
                     {
                     {
-                        // Normalize aspect ratio if invalid
-                        foreach (var stream in result.streams)
+                        if (result.streams != null)
                         {
                         {
-                            if (string.Equals(stream.display_aspect_ratio, "0:1", StringComparison.OrdinalIgnoreCase))
-                            {
-                                stream.display_aspect_ratio = string.Empty;
-                            }
-                            if (string.Equals(stream.sample_aspect_ratio, "0:1", StringComparison.OrdinalIgnoreCase))
+                            // Normalize aspect ratio if invalid
+                            foreach (var stream in result.streams)
                             {
                             {
-                                stream.sample_aspect_ratio = string.Empty;
+                                if (string.Equals(stream.display_aspect_ratio, "0:1", StringComparison.OrdinalIgnoreCase))
+                                {
+                                    stream.display_aspect_ratio = string.Empty;
+                                }
+                                if (string.Equals(stream.sample_aspect_ratio, "0:1", StringComparison.OrdinalIgnoreCase))
+                                {
+                                    stream.sample_aspect_ratio = string.Empty;
+                                }
                             }
                             }
                         }
                         }
-                    }
 
 
-                    var mediaInfo = new ProbeResultNormalizer(_logger, FileSystem).GetMediaInfo(result, videoType, isAudio, primaryPath, protocol);
+                        var mediaInfo = new ProbeResultNormalizer(_logger, FileSystem).GetMediaInfo(result, videoType, isAudio, primaryPath, protocol);
 
 
-                    if (extractKeyFrameInterval && mediaInfo.RunTimeTicks.HasValue)
-                    {
-                        foreach (var stream in mediaInfo.MediaStreams)
+                        if (extractKeyFrameInterval && mediaInfo.RunTimeTicks.HasValue)
                         {
                         {
-                            if (stream.Type == MediaStreamType.Video && string.Equals(stream.Codec, "h264", StringComparison.OrdinalIgnoreCase))
+                            foreach (var stream in mediaInfo.MediaStreams)
                             {
                             {
-                                try
-                                {
-                                    //stream.KeyFrames = await GetKeyFrames(inputPath, stream.Index, cancellationToken)
-                                    //            .ConfigureAwait(false);
-                                }
-                                catch (OperationCanceledException)
-                                {
-
-                                }
-                                catch (Exception ex)
+                                if (stream.Type == MediaStreamType.Video && string.Equals(stream.Codec, "h264", StringComparison.OrdinalIgnoreCase))
                                 {
                                 {
-                                    _logger.ErrorException("Error getting key frame interval", ex);
+                                    try
+                                    {
+                                        //stream.KeyFrames = await GetKeyFrames(inputPath, stream.Index, cancellationToken)
+                                        //            .ConfigureAwait(false);
+                                    }
+                                    catch (OperationCanceledException)
+                                    {
+
+                                    }
+                                    catch (Exception ex)
+                                    {
+                                        _logger.ErrorException("Error getting key frame interval", ex);
+                                    }
                                 }
                                 }
                             }
                             }
                         }
                         }
-                    }
 
 
-                    return mediaInfo;
+                        return mediaInfo;
+                    }
                 }
                 }
-            }
-            catch
-            {
-                StopProcess(processWrapper, 100, true);
+                catch
+                {
+                    StopProcess(processWrapper, 100, true);
 
 
-                throw;
-            }
-            finally
-            {
-                _ffProbeResourcePool.Release();
+                    throw;
+                }
+                finally
+                {
+                    _ffProbeResourcePool.Release();
+                }
             }
             }
 
 
             throw new ApplicationException(string.Format("FFProbe failed for {0}", inputPath));
             throw new ApplicationException(string.Format("FFProbe failed for {0}", inputPath));
@@ -307,31 +308,32 @@ namespace MediaBrowser.MediaEncoding.Encoder
 
 
             _logger.Debug("{0} {1}", process.StartInfo.FileName, process.StartInfo.Arguments);
             _logger.Debug("{0} {1}", process.StartInfo.FileName, process.StartInfo.Arguments);
 
 
-            var processWrapper = new ProcessWrapper(process, this);
-
-            StartProcess(processWrapper);
+            using (var processWrapper = new ProcessWrapper(process, this))
+            {
+                StartProcess(processWrapper);
 
 
-            var lines = new List<int>();
+                var lines = new List<int>();
 
 
-            try
-            {
-                process.BeginErrorReadLine();
+                try
+                {
+                    process.BeginErrorReadLine();
 
 
-                await StartReadingOutput(process.StandardOutput.BaseStream, lines, 120000, cancellationToken).ConfigureAwait(false);
-            }
-            catch (OperationCanceledException)
-            {
-                if (cancellationToken.IsCancellationRequested)
+                    await StartReadingOutput(process.StandardOutput.BaseStream, lines, 120000, cancellationToken).ConfigureAwait(false);
+                }
+                catch (OperationCanceledException)
                 {
                 {
-                    throw;
+                    if (cancellationToken.IsCancellationRequested)
+                    {
+                        throw;
+                    }
+                }
+                finally
+                {
+                    StopProcess(processWrapper, 100, true);
                 }
                 }
-            }
-            finally
-            {
-                StopProcess(processWrapper, 100, true);
-            }
 
 
-            return lines;
+                return lines;
+            }
         }
         }
 
 
         private async Task StartReadingOutput(Stream source, List<int> lines, int timeoutMs, CancellationToken cancellationToken)
         private async Task StartReadingOutput(Stream source, List<int> lines, int timeoutMs, CancellationToken cancellationToken)
@@ -490,51 +492,53 @@ namespace MediaBrowser.MediaEncoding.Encoder
 
 
             await resourcePool.WaitAsync(cancellationToken).ConfigureAwait(false);
             await resourcePool.WaitAsync(cancellationToken).ConfigureAwait(false);
 
 
-            var processWrapper = new ProcessWrapper(process, this);
-            bool ranToCompletion;
+            using (var processWrapper = new ProcessWrapper(process, this))
+            {
+                bool ranToCompletion;
 
 
-            var memoryStream = new MemoryStream();
+                var memoryStream = new MemoryStream();
 
 
-            try
-            {
-                StartProcess(processWrapper);
+                try
+                {
+                    StartProcess(processWrapper);
 
 
 #pragma warning disable 4014
 #pragma warning disable 4014
-                // Important - don't await the log task or we won't be able to kill ffmpeg when the user stops playback
-                process.StandardOutput.BaseStream.CopyToAsync(memoryStream);
+                    // Important - don't await the log task or we won't be able to kill ffmpeg when the user stops playback
+                    process.StandardOutput.BaseStream.CopyToAsync(memoryStream);
 #pragma warning restore 4014
 #pragma warning restore 4014
 
 
-                // MUST read both stdout and stderr asynchronously or a deadlock may occurr
-                process.BeginErrorReadLine();
+                    // MUST read both stdout and stderr asynchronously or a deadlock may occurr
+                    process.BeginErrorReadLine();
 
 
-                ranToCompletion = process.WaitForExit(10000);
+                    ranToCompletion = process.WaitForExit(10000);
 
 
-                if (!ranToCompletion)
+                    if (!ranToCompletion)
+                    {
+                        StopProcess(processWrapper, 1000, false);
+                    }
+
+                }
+                finally
                 {
                 {
-                    StopProcess(processWrapper, 1000, false);
+                    resourcePool.Release();
                 }
                 }
 
 
-            }
-            finally
-            {
-                resourcePool.Release();
-            }
+                var exitCode = ranToCompletion ? processWrapper.ExitCode ?? 0 : -1;
 
 
-            var exitCode = ranToCompletion ? processWrapper.ExitCode ?? 0 : -1;
+                if (exitCode == -1 || memoryStream.Length == 0)
+                {
+                    memoryStream.Dispose();
 
 
-            if (exitCode == -1 || memoryStream.Length == 0)
-            {
-                memoryStream.Dispose();
+                    var msg = string.Format("ffmpeg image extraction failed for {0}", inputPath);
 
 
-                var msg = string.Format("ffmpeg image extraction failed for {0}", inputPath);
+                    _logger.Error(msg);
 
 
-                _logger.Error(msg);
+                    throw new ApplicationException(msg);
+                }
 
 
-                throw new ApplicationException(msg);
+                memoryStream.Position = 0;
+                return memoryStream;
             }
             }
-
-            memoryStream.Position = 0;
-            return memoryStream;
         }
         }
 
 
         public string GetTimeParameter(long ticks)
         public string GetTimeParameter(long ticks)
@@ -603,55 +607,56 @@ namespace MediaBrowser.MediaEncoding.Encoder
 
 
             bool ranToCompletion = false;
             bool ranToCompletion = false;
 
 
-            var processWrapper = new ProcessWrapper(process, this);
-
-            try
+            using (var processWrapper = new ProcessWrapper(process, this))
             {
             {
-                StartProcess(processWrapper);
+                try
+                {
+                    StartProcess(processWrapper);
 
 
-                // Need to give ffmpeg enough time to make all the thumbnails, which could be a while,
-                // but we still need to detect if the process hangs.
-                // Making the assumption that as long as new jpegs are showing up, everything is good.
+                    // Need to give ffmpeg enough time to make all the thumbnails, which could be a while,
+                    // but we still need to detect if the process hangs.
+                    // Making the assumption that as long as new jpegs are showing up, everything is good.
 
 
-                bool isResponsive = true;
-                int lastCount = 0;
+                    bool isResponsive = true;
+                    int lastCount = 0;
 
 
-                while (isResponsive)
-                {
-                    if (process.WaitForExit(30000))
+                    while (isResponsive)
                     {
                     {
-                        ranToCompletion = true;
-                        break;
-                    }
+                        if (process.WaitForExit(30000))
+                        {
+                            ranToCompletion = true;
+                            break;
+                        }
+
+                        cancellationToken.ThrowIfCancellationRequested();
 
 
-                    cancellationToken.ThrowIfCancellationRequested();
+                        var jpegCount = Directory.GetFiles(targetDirectory)
+                            .Count(i => string.Equals(Path.GetExtension(i), ".jpg", StringComparison.OrdinalIgnoreCase));
 
 
-                    var jpegCount = Directory.GetFiles(targetDirectory)
-                        .Count(i => string.Equals(Path.GetExtension(i), ".jpg", StringComparison.OrdinalIgnoreCase));
+                        isResponsive = (jpegCount > lastCount);
+                        lastCount = jpegCount;
+                    }
 
 
-                    isResponsive = (jpegCount > lastCount);
-                    lastCount = jpegCount;
+                    if (!ranToCompletion)
+                    {
+                        StopProcess(processWrapper, 1000, false);
+                    }
                 }
                 }
-
-                if (!ranToCompletion)
+                finally
                 {
                 {
-                    StopProcess(processWrapper, 1000, false);
+                    resourcePool.Release();
                 }
                 }
-            }
-            finally
-            {
-                resourcePool.Release();
-            }
 
 
-            var exitCode = ranToCompletion ? processWrapper.ExitCode ?? 0 : -1;
+                var exitCode = ranToCompletion ? processWrapper.ExitCode ?? 0 : -1;
 
 
-            if (exitCode == -1)
-            {
-                var msg = string.Format("ffmpeg image extraction failed for {0}", inputArgument);
+                if (exitCode == -1)
+                {
+                    var msg = string.Format("ffmpeg image extraction failed for {0}", inputArgument);
 
 
-                _logger.Error(msg);
+                    _logger.Error(msg);
 
 
-                throw new ApplicationException(msg);
+                    throw new ApplicationException(msg);
+                }
             }
             }
         }
         }
 
 
@@ -781,7 +786,7 @@ namespace MediaBrowser.MediaEncoding.Encoder
             }
             }
         }
         }
 
 
-        private class ProcessWrapper
+        private class ProcessWrapper : IDisposable
         {
         {
             public readonly Process Process;
             public readonly Process Process;
             public bool HasExited;
             public bool HasExited;
@@ -810,6 +815,25 @@ namespace MediaBrowser.MediaEncoding.Encoder
 
 
                 process.Dispose();
                 process.Dispose();
             }
             }
+
+            private bool _disposed;
+            private readonly object _syncLock = new object();
+            public void Dispose()
+            {
+                lock (_syncLock)
+                {
+                    if (!_disposed)
+                    {
+                        if (Process != null)
+                        {
+                            Process.Exited -= Process_Exited;
+                            Process.Dispose();
+                        }
+                    }
+
+                    _disposed = true;
+                }
+            }
         }
         }
     }
     }
 }
 }

+ 0 - 2
MediaBrowser.MediaEncoding/Encoder/VideoEncoder.cs

@@ -1,8 +1,6 @@
 using MediaBrowser.Common.IO;
 using MediaBrowser.Common.IO;
-using MediaBrowser.Controller.Channels;
 using MediaBrowser.Controller.Configuration;
 using MediaBrowser.Controller.Configuration;
 using MediaBrowser.Controller.Library;
 using MediaBrowser.Controller.Library;
-using MediaBrowser.Controller.LiveTv;
 using MediaBrowser.Controller.MediaEncoding;
 using MediaBrowser.Controller.MediaEncoding;
 using MediaBrowser.Controller.Session;
 using MediaBrowser.Controller.Session;
 using MediaBrowser.Model.Dlna;
 using MediaBrowser.Model.Dlna;

+ 6 - 0
MediaBrowser.Model/ApiClient/IApiClient.cs

@@ -1499,5 +1499,11 @@ namespace MediaBrowser.Model.ApiClient
         /// <param name="itemIds">The item ids.</param>
         /// <param name="itemIds">The item ids.</param>
         /// <returns>Task.</returns>
         /// <returns>Task.</returns>
         Task CancelSyncLibraryItems(string targetId, IEnumerable<string> itemIds);
         Task CancelSyncLibraryItems(string targetId, IEnumerable<string> itemIds);
+        /// <summary>
+        /// Gets the supported bitrate.
+        /// </summary>
+        /// <param name="cancellationToken">The cancellation token.</param>
+        /// <returns>Task&lt;System.Int32&gt;.</returns>
+        Task<int> GetSupportedBitrate(CancellationToken cancellationToken);
     }
     }
 }
 }

+ 2 - 4
MediaBrowser.Model/Configuration/ServerConfiguration.cs

@@ -158,7 +158,7 @@ namespace MediaBrowser.Model.Configuration
         /// different directories and files.
         /// different directories and files.
         /// </summary>
         /// </summary>
         /// <value>The file watcher delay.</value>
         /// <value>The file watcher delay.</value>
-        public int RealtimeMonitorDelay { get; set; }
+        public int RealtimeLibraryMonitorDelay { get; set; }
 
 
         /// <summary>
         /// <summary>
         /// Gets or sets a value indicating whether [enable dashboard response caching].
         /// Gets or sets a value indicating whether [enable dashboard response caching].
@@ -233,7 +233,7 @@ namespace MediaBrowser.Model.Configuration
             // 5 minutes
             // 5 minutes
             MinResumeDurationSeconds = 300;
             MinResumeDurationSeconds = 300;
 
 
-            RealtimeMonitorDelay = 30;
+            RealtimeLibraryMonitorDelay = 40;
 
 
             EnableInternetProviders = true;
             EnableInternetProviders = true;
             FindInternetTrailers = true;
             FindInternetTrailers = true;
@@ -261,8 +261,6 @@ namespace MediaBrowser.Model.Configuration
                 "Chromecast",
                 "Chromecast",
                 "iOS",
                 "iOS",
                 "Unknown app",
                 "Unknown app",
-                "MediaPortal",
-                "Media Portal",
                 "iPad",
                 "iPad",
                 "iPhone",
                 "iPhone",
                 "Windows Phone"
                 "Windows Phone"

+ 3 - 1
MediaBrowser.Model/Configuration/UserConfiguration.cs

@@ -32,6 +32,7 @@ namespace MediaBrowser.Model.Configuration
         public string[] DisplayChannelsWithinViews { get; set; }
         public string[] DisplayChannelsWithinViews { get; set; }
 
 
         public string[] ExcludeFoldersFromGrouping { get; set; }
         public string[] ExcludeFoldersFromGrouping { get; set; }
+        public string[] GroupedFolders { get; set; }
 
 
         public SubtitlePlaybackMode SubtitleMode { get; set; }
         public SubtitlePlaybackMode SubtitleMode { get; set; }
         public bool DisplayCollectionsView { get; set; }
         public bool DisplayCollectionsView { get; set; }
@@ -62,12 +63,13 @@ namespace MediaBrowser.Model.Configuration
             OrderedViews = new string[] { };
             OrderedViews = new string[] { };
             DisplayChannelsWithinViews = new string[] { };
             DisplayChannelsWithinViews = new string[] { };
 
 
-            ExcludeFoldersFromGrouping = new string[] { };
             PlainFolderViews = new string[] { };
             PlainFolderViews = new string[] { };
             DisplayCollectionsView = true;
             DisplayCollectionsView = true;
 
 
             IncludeTrailersInSuggestions = true;
             IncludeTrailersInSuggestions = true;
             EnableCinemaMode = true;
             EnableCinemaMode = true;
+
+            GroupedFolders = new string[] { };
         }
         }
     }
     }
 }
 }

+ 26 - 1
MediaBrowser.Model/Dlna/CodecProfile.cs

@@ -14,6 +14,9 @@ namespace MediaBrowser.Model.Dlna
         [XmlAttribute("codec")]
         [XmlAttribute("codec")]
         public string Codec { get; set; }
         public string Codec { get; set; }
 
 
+        [XmlAttribute("container")]
+        public string Container { get; set; }
+
         public CodecProfile()
         public CodecProfile()
         {
         {
             Conditions = new ProfileCondition[] {};
             Conditions = new ProfileCondition[] {};
@@ -29,8 +32,30 @@ namespace MediaBrowser.Model.Dlna
             return list;
             return list;
         }
         }
 
 
-        public bool ContainsCodec(string codec)
+        public List<string> GetContainers()
+        {
+            List<string> list = new List<string>();
+            foreach (string i in (Container ?? string.Empty).Split(','))
+            {
+                if (!string.IsNullOrEmpty(i)) list.Add(i);
+            }
+            return list;
+        }
+
+        private bool ContainsContainer(string container)
+        {
+            List<string> containers = GetContainers();
+
+            return containers.Count == 0 || ListHelper.ContainsIgnoreCase(containers, container ?? string.Empty);
+        }
+
+        public bool ContainsCodec(string codec, string container)
         {
         {
+            if (!ContainsContainer(container))
+            {
+                return false;
+            }
+
             List<string> codecs = GetCodecs();
             List<string> codecs = GetCodecs();
 
 
             return codecs.Count == 0 || ListHelper.ContainsIgnoreCase(codecs, codec);
             return codecs.Count == 0 || ListHelper.ContainsIgnoreCase(codecs, codec);

+ 0 - 6
MediaBrowser.Model/Dlna/ConditionProcessor.cs

@@ -7,8 +7,6 @@ namespace MediaBrowser.Model.Dlna
     public class ConditionProcessor
     public class ConditionProcessor
     {
     {
         public bool IsVideoConditionSatisfied(ProfileCondition condition,
         public bool IsVideoConditionSatisfied(ProfileCondition condition,
-            int? audioBitrate,
-            int? audioChannels,
             int? width,
             int? width,
             int? height,
             int? height,
             int? bitDepth,
             int? bitDepth,
@@ -44,10 +42,6 @@ namespace MediaBrowser.Model.Dlna
                     return IsConditionSatisfied(condition, videoProfile);
                     return IsConditionSatisfied(condition, videoProfile);
                 case ProfileConditionValue.PacketLength:
                 case ProfileConditionValue.PacketLength:
                     return IsConditionSatisfied(condition, packetLength);
                     return IsConditionSatisfied(condition, packetLength);
-                case ProfileConditionValue.AudioBitrate:
-                    return IsConditionSatisfied(condition, audioBitrate);
-                case ProfileConditionValue.AudioChannels:
-                    return IsConditionSatisfied(condition, audioChannels);
                 case ProfileConditionValue.VideoBitDepth:
                 case ProfileConditionValue.VideoBitDepth:
                     return IsConditionSatisfied(condition, bitDepth);
                     return IsConditionSatisfied(condition, bitDepth);
                 case ProfileConditionValue.VideoBitrate:
                 case ProfileConditionValue.VideoBitrate:

+ 2 - 5
MediaBrowser.Model/Dlna/ContentFeatureBuilder.cs

@@ -1,4 +1,5 @@
 using MediaBrowser.Model.MediaInfo;
 using MediaBrowser.Model.MediaInfo;
+using System;
 using System.Collections.Generic;
 using System.Collections.Generic;
 
 
 namespace MediaBrowser.Model.Dlna
 namespace MediaBrowser.Model.Dlna
@@ -105,8 +106,6 @@ namespace MediaBrowser.Model.Dlna
             int? height,
             int? height,
             int? bitDepth,
             int? bitDepth,
             int? videoBitrate,
             int? videoBitrate,
-            int? audioChannels,
-            int? audioBitrate,
             TransportStreamTimestamp timestamp,
             TransportStreamTimestamp timestamp,
             bool isDirectStream,
             bool isDirectStream,
             long? runtimeTicks,
             long? runtimeTicks,
@@ -147,8 +146,6 @@ namespace MediaBrowser.Model.Dlna
             ResponseProfile mediaProfile = _profile.GetVideoMediaProfile(container,
             ResponseProfile mediaProfile = _profile.GetVideoMediaProfile(container,
                 audioCodec,
                 audioCodec,
                 videoCodec,
                 videoCodec,
-                audioBitrate,
-                audioChannels,
                 width,
                 width,
                 height,
                 height,
                 bitDepth,
                 bitDepth,
@@ -168,7 +165,7 @@ namespace MediaBrowser.Model.Dlna
 
 
             if (mediaProfile != null && !string.IsNullOrEmpty(mediaProfile.OrgPn))
             if (mediaProfile != null && !string.IsNullOrEmpty(mediaProfile.OrgPn))
             {
             {
-                orgPnValues.Add(mediaProfile.OrgPn);
+                orgPnValues.AddRange(mediaProfile.OrgPn.Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries));
             }
             }
             else
             else
             {
             {

+ 1 - 4
MediaBrowser.Model/Dlna/DeviceProfile.cs

@@ -34,7 +34,6 @@ namespace MediaBrowser.Model.Dlna
         public string ModelNumber { get; set; }
         public string ModelNumber { get; set; }
         public string ModelUrl { get; set; }
         public string ModelUrl { get; set; }
         public string SerialNumber { get; set; }
         public string SerialNumber { get; set; }
-        public bool IgnoreTranscodeByteRangeRequests { get; set; }
 
 
         public bool EnableAlbumArtInDidl { get; set; }
         public bool EnableAlbumArtInDidl { get; set; }
         public bool EnableSingleAlbumArtLimit { get; set; }
         public bool EnableSingleAlbumArtLimit { get; set; }
@@ -272,8 +271,6 @@ namespace MediaBrowser.Model.Dlna
         public ResponseProfile GetVideoMediaProfile(string container, 
         public ResponseProfile GetVideoMediaProfile(string container, 
             string audioCodec,
             string audioCodec,
             string videoCodec,
             string videoCodec,
-            int? audioBitrate,
-            int? audioChannels,
             int? width,
             int? width,
             int? height,
             int? height,
             int? bitDepth,
             int? bitDepth,
@@ -321,7 +318,7 @@ namespace MediaBrowser.Model.Dlna
                 var anyOff = false;
                 var anyOff = false;
                 foreach (ProfileCondition c in i.Conditions)
                 foreach (ProfileCondition c in i.Conditions)
                 {
                 {
-                    if (!conditionProcessor.IsVideoConditionSatisfied(c, audioBitrate, audioChannels, width, height, bitDepth, videoBitrate, videoProfile, videoLevel, videoFramerate, packetLength, timestamp, isAnamorphic, isCabac, refFrames, numVideoStreams, numAudioStreams))
+                    if (!conditionProcessor.IsVideoConditionSatisfied(c, width, height, bitDepth, videoBitrate, videoProfile, videoLevel, videoFramerate, packetLength, timestamp, isAnamorphic, isCabac, refFrames, numVideoStreams, numAudioStreams))
                     {
                     {
                         anyOff = true;
                         anyOff = true;
                         break;
                         break;

+ 8 - 8
MediaBrowser.Model/Dlna/StreamBuilder.cs

@@ -131,7 +131,7 @@ namespace MediaBrowser.Model.Dlna
                     List<ProfileCondition> conditions = new List<ProfileCondition>();
                     List<ProfileCondition> conditions = new List<ProfileCondition>();
                     foreach (CodecProfile i in options.Profile.CodecProfiles)
                     foreach (CodecProfile i in options.Profile.CodecProfiles)
                     {
                     {
-                        if (i.Type == CodecType.Audio && i.ContainsCodec(audioCodec))
+                        if (i.Type == CodecType.Audio && i.ContainsCodec(audioCodec, item.Container))
                         {
                         {
                             foreach (ProfileCondition c in i.Conditions)
                             foreach (ProfileCondition c in i.Conditions)
                             {
                             {
@@ -206,7 +206,7 @@ namespace MediaBrowser.Model.Dlna
                 List<CodecProfile> audioCodecProfiles = new List<CodecProfile>();
                 List<CodecProfile> audioCodecProfiles = new List<CodecProfile>();
                 foreach (CodecProfile i in options.Profile.CodecProfiles)
                 foreach (CodecProfile i in options.Profile.CodecProfiles)
                 {
                 {
-                    if (i.Type == CodecType.Audio && i.ContainsCodec(transcodingProfile.AudioCodec))
+                    if (i.Type == CodecType.Audio && i.ContainsCodec(transcodingProfile.AudioCodec, transcodingProfile.Container))
                     {
                     {
                         audioCodecProfiles.Add(i);
                         audioCodecProfiles.Add(i);
                     }
                     }
@@ -423,7 +423,7 @@ namespace MediaBrowser.Model.Dlna
                 List<ProfileCondition> videoTranscodingConditions = new List<ProfileCondition>();
                 List<ProfileCondition> videoTranscodingConditions = new List<ProfileCondition>();
                 foreach (CodecProfile i in options.Profile.CodecProfiles)
                 foreach (CodecProfile i in options.Profile.CodecProfiles)
                 {
                 {
-                    if (i.Type == CodecType.Video && i.ContainsCodec(transcodingProfile.VideoCodec))
+                    if (i.Type == CodecType.Video && i.ContainsCodec(transcodingProfile.VideoCodec, transcodingProfile.Container))
                     {
                     {
                         foreach (ProfileCondition c in i.Conditions)
                         foreach (ProfileCondition c in i.Conditions)
                         {
                         {
@@ -437,7 +437,7 @@ namespace MediaBrowser.Model.Dlna
                 List<ProfileCondition> audioTranscodingConditions = new List<ProfileCondition>();
                 List<ProfileCondition> audioTranscodingConditions = new List<ProfileCondition>();
                 foreach (CodecProfile i in options.Profile.CodecProfiles)
                 foreach (CodecProfile i in options.Profile.CodecProfiles)
                 {
                 {
-                    if (i.Type == CodecType.VideoAudio && i.ContainsCodec(transcodingProfile.AudioCodec))
+                    if (i.Type == CodecType.VideoAudio && i.ContainsCodec(transcodingProfile.AudioCodec, transcodingProfile.Container))
                     {
                     {
                         foreach (ProfileCondition c in i.Conditions)
                         foreach (ProfileCondition c in i.Conditions)
                         {
                         {
@@ -578,7 +578,7 @@ namespace MediaBrowser.Model.Dlna
             // Check container conditions
             // Check container conditions
             foreach (ProfileCondition i in conditions)
             foreach (ProfileCondition i in conditions)
             {
             {
-                if (!conditionProcessor.IsVideoConditionSatisfied(i, audioBitrate, audioChannels, width, height, bitDepth, videoBitrate, videoProfile, videoLevel, videoFramerate, packetLength, timestamp, isAnamorphic, isCabac, refFrames, numVideoStreams, numAudioStreams))
+                if (!conditionProcessor.IsVideoConditionSatisfied(i, width, height, bitDepth, videoBitrate, videoProfile, videoLevel, videoFramerate, packetLength, timestamp, isAnamorphic, isCabac, refFrames, numVideoStreams, numAudioStreams))
                 {
                 {
                     LogConditionFailure(profile, "VideoContainerProfile", i, mediaSource);
                     LogConditionFailure(profile, "VideoContainerProfile", i, mediaSource);
 
 
@@ -600,7 +600,7 @@ namespace MediaBrowser.Model.Dlna
             conditions = new List<ProfileCondition>();
             conditions = new List<ProfileCondition>();
             foreach (CodecProfile i in profile.CodecProfiles)
             foreach (CodecProfile i in profile.CodecProfiles)
             {
             {
-                if (i.Type == CodecType.Video && i.ContainsCodec(videoCodec))
+                if (i.Type == CodecType.Video && i.ContainsCodec(videoCodec, container))
                 {
                 {
                     foreach (ProfileCondition c in i.Conditions)
                     foreach (ProfileCondition c in i.Conditions)
                     {
                     {
@@ -611,7 +611,7 @@ namespace MediaBrowser.Model.Dlna
 
 
             foreach (ProfileCondition i in conditions)
             foreach (ProfileCondition i in conditions)
             {
             {
-                if (!conditionProcessor.IsVideoConditionSatisfied(i, audioBitrate, audioChannels, width, height, bitDepth, videoBitrate, videoProfile, videoLevel, videoFramerate, packetLength, timestamp, isAnamorphic, isCabac, refFrames, numVideoStreams, numAudioStreams))
+                if (!conditionProcessor.IsVideoConditionSatisfied(i, width, height, bitDepth, videoBitrate, videoProfile, videoLevel, videoFramerate, packetLength, timestamp, isAnamorphic, isCabac, refFrames, numVideoStreams, numAudioStreams))
                 {
                 {
                     LogConditionFailure(profile, "VideoCodecProfile", i, mediaSource);
                     LogConditionFailure(profile, "VideoCodecProfile", i, mediaSource);
 
 
@@ -635,7 +635,7 @@ namespace MediaBrowser.Model.Dlna
                 conditions = new List<ProfileCondition>();
                 conditions = new List<ProfileCondition>();
                 foreach (CodecProfile i in profile.CodecProfiles)
                 foreach (CodecProfile i in profile.CodecProfiles)
                 {
                 {
-                    if (i.Type == CodecType.VideoAudio && i.ContainsCodec(audioCodec))
+                    if (i.Type == CodecType.VideoAudio && i.ContainsCodec(audioCodec, container))
                     {
                     {
                         foreach (ProfileCondition c in i.Conditions)
                         foreach (ProfileCondition c in i.Conditions)
                         {
                         {

+ 14 - 16
MediaBrowser.Providers/Manager/ItemImageProvider.cs

@@ -38,13 +38,16 @@ namespace MediaBrowser.Providers.Manager
         {
         {
             var hasChanges = false;
             var hasChanges = false;
 
 
-            var images = providers.OfType<ILocalImageFileProvider>()
-                .SelectMany(i => i.GetImages(item, directoryService))
-                .ToList();
-
-            if (MergeImages(item, images))
+            if (!(item is Photo))
             {
             {
-                hasChanges = true;
+                var images = providers.OfType<ILocalImageFileProvider>()
+                    .SelectMany(i => i.GetImages(item, directoryService))
+                    .ToList();
+
+                if (MergeImages(item, images))
+                {
+                    hasChanges = true;
+                }
             }
             }
 
 
             return hasChanges;
             return hasChanges;
@@ -419,19 +422,14 @@ namespace MediaBrowser.Providers.Manager
             var changed = false;
             var changed = false;
 
 
             var newImages = images.Where(i => i.Type == type).ToList();
             var newImages = images.Where(i => i.Type == type).ToList();
-            if (newImages.Count > 0)
-            {
-                var newImageFileInfos = images.Where(i => i.Type == type)
+
+            var newImageFileInfos = newImages
                     .Select(i => i.FileInfo)
                     .Select(i => i.FileInfo)
                     .ToList();
                     .ToList();
 
 
-                if (newImageFileInfos.Count > 0)
-                {
-                    if (item.AddImages(type, newImageFileInfos))
-                    {
-                        changed = true;
-                    }
-                }
+            if (item.AddImages(type, newImageFileInfos))
+            {
+                changed = true;
             }
             }
 
 
             return changed;
             return changed;

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

@@ -14,6 +14,15 @@ namespace MediaBrowser.Providers.Manager
             bool replaceData, 
             bool replaceData, 
             bool mergeMetadataSettings)
             bool mergeMetadataSettings)
         {
         {
+            if (source == null)
+            {
+                throw new ArgumentNullException("source");
+            }
+            if (target == null)
+            {
+                throw new ArgumentNullException("target");
+            }
+
             if (!lockedFields.Contains(MetadataFields.Name))
             if (!lockedFields.Contains(MetadataFields.Name))
             {
             {
                 if (replaceData || string.IsNullOrEmpty(target.Name))
                 if (replaceData || string.IsNullOrEmpty(target.Name))

+ 1 - 1
MediaBrowser.Providers/MediaInfo/AudioImageProvider.cs

@@ -93,7 +93,7 @@ namespace MediaBrowser.Providers.MediaInfo
 
 
         private string GetAudioImagePath(Audio item)
         private string GetAudioImagePath(Audio item)
         {
         {
-            var album = item.Parent as MusicAlbum;
+            var album = item.AlbumEntity;
 
 
             var filename = item.Album ?? string.Empty;
             var filename = item.Album ?? string.Empty;
             filename += string.Join(",", item.Artists.ToArray());
             filename += string.Join(",", item.Artists.ToArray());

+ 11 - 4
MediaBrowser.Providers/TV/TvdbEpisodeProvider.cs

@@ -5,6 +5,7 @@ using MediaBrowser.Controller.Entities;
 using MediaBrowser.Controller.Entities.TV;
 using MediaBrowser.Controller.Entities.TV;
 using MediaBrowser.Controller.Providers;
 using MediaBrowser.Controller.Providers;
 using MediaBrowser.Model.Entities;
 using MediaBrowser.Model.Entities;
+using MediaBrowser.Model.Logging;
 using MediaBrowser.Model.Providers;
 using MediaBrowser.Model.Providers;
 using System;
 using System;
 using System.Collections.Generic;
 using System.Collections.Generic;
@@ -29,12 +30,14 @@ namespace MediaBrowser.Providers.TV
         private readonly IFileSystem _fileSystem;
         private readonly IFileSystem _fileSystem;
         private readonly IServerConfigurationManager _config;
         private readonly IServerConfigurationManager _config;
         private readonly IHttpClient _httpClient;
         private readonly IHttpClient _httpClient;
+        private readonly ILogger _logger;
 
 
-        public TvdbEpisodeProvider(IFileSystem fileSystem, IServerConfigurationManager config, IHttpClient httpClient)
+        public TvdbEpisodeProvider(IFileSystem fileSystem, IServerConfigurationManager config, IHttpClient httpClient, ILogger logger)
         {
         {
             _fileSystem = fileSystem;
             _fileSystem = fileSystem;
             _config = config;
             _config = config;
             _httpClient = httpClient;
             _httpClient = httpClient;
+            _logger = logger;
             Current = this;
             Current = this;
         }
         }
 
 
@@ -100,7 +103,8 @@ namespace MediaBrowser.Providers.TV
 
 
                 try
                 try
                 {
                 {
-                    result.Item = FetchEpisodeData(searchInfo, identity, seriesDataPath, searchInfo.SeriesProviderIds, cancellationToken);
+                    result.Item = FetchEpisodeData(searchInfo, identity, seriesDataPath, searchInfo.SeriesProviderIds,
+                        cancellationToken);
                     result.HasMetadata = result.Item != null;
                     result.HasMetadata = result.Item != null;
                 }
                 }
                 catch (FileNotFoundException)
                 catch (FileNotFoundException)
@@ -112,6 +116,10 @@ namespace MediaBrowser.Providers.TV
                     // Don't fail the provider because this will just keep on going and going.
                     // Don't fail the provider because this will just keep on going and going.
                 }
                 }
             }
             }
+            else
+            {
+                _logger.Debug("No series identity found for {0}", searchInfo.Name);
+            }
 
 
             return result;
             return result;
         }
         }
@@ -265,7 +273,6 @@ namespace MediaBrowser.Providers.TV
 
 
                 FetchMainEpisodeInfo(episode, file, cancellationToken);
                 FetchMainEpisodeInfo(episode, file, cancellationToken);
                 usingAbsoluteData = true;
                 usingAbsoluteData = true;
-                success = true;
             }
             }
 
 
             var end = identity.IndexNumberEnd ?? episodeNumber;
             var end = identity.IndexNumberEnd ?? episodeNumber;
@@ -298,7 +305,7 @@ namespace MediaBrowser.Providers.TV
                 episodeNumber++;
                 episodeNumber++;
             }
             }
 
 
-            return success ? episode : null;
+            return episode;
         }
         }
 
 
         private readonly CultureInfo _usCulture = new CultureInfo("en-US");
         private readonly CultureInfo _usCulture = new CultureInfo("en-US");

+ 1 - 10
MediaBrowser.Server.Implementations/Dto/DtoService.cs

@@ -1193,7 +1193,7 @@ namespace MediaBrowser.Server.Implementations.Dto
             {
             {
                 dto.Album = audio.Album;
                 dto.Album = audio.Album;
 
 
-                var albumParent = audio.FindParent<MusicAlbum>();
+                var albumParent = audio.AlbumEntity;
 
 
                 if (albumParent != null)
                 if (albumParent != null)
                 {
                 {
@@ -1208,15 +1208,6 @@ namespace MediaBrowser.Server.Implementations.Dto
                 //}
                 //}
             }
             }
 
 
-            var album = item as MusicAlbum;
-
-            if (album != null)
-            {
-                dto.SoundtrackIds = album.SoundtrackIds
-                    .Select(i => i.ToString("N"))
-                    .ToArray();
-            }
-
             var hasArtist = item as IHasArtist;
             var hasArtist = item as IHasArtist;
             if (hasArtist != null)
             if (hasArtist != null)
             {
             {

+ 23 - 5
MediaBrowser.Server.Implementations/EntryPoints/ExternalPortForwarding.cs

@@ -1,5 +1,6 @@
 using MediaBrowser.Controller;
 using MediaBrowser.Controller;
 using MediaBrowser.Controller.Configuration;
 using MediaBrowser.Controller.Configuration;
+using MediaBrowser.Controller.Dlna;
 using MediaBrowser.Controller.Plugins;
 using MediaBrowser.Controller.Plugins;
 using MediaBrowser.Model.Logging;
 using MediaBrowser.Model.Logging;
 using Mono.Nat;
 using Mono.Nat;
@@ -7,6 +8,7 @@ using System;
 using System.Collections.Generic;
 using System.Collections.Generic;
 using System.Globalization;
 using System.Globalization;
 using System.IO;
 using System.IO;
+using System.Net;
 using System.Text;
 using System.Text;
 using System.Threading;
 using System.Threading;
 
 
@@ -17,15 +19,17 @@ namespace MediaBrowser.Server.Implementations.EntryPoints
         private readonly IServerApplicationHost _appHost;
         private readonly IServerApplicationHost _appHost;
         private readonly ILogger _logger;
         private readonly ILogger _logger;
         private readonly IServerConfigurationManager _config;
         private readonly IServerConfigurationManager _config;
+        private readonly ISsdpHandler _ssdp;
 
 
         private Timer _timer;
         private Timer _timer;
         private bool _isStarted;
         private bool _isStarted;
 
 
-        public ExternalPortForwarding(ILogManager logmanager, IServerApplicationHost appHost, IServerConfigurationManager config)
+        public ExternalPortForwarding(ILogManager logmanager, IServerApplicationHost appHost, IServerConfigurationManager config, ISsdpHandler ssdp)
         {
         {
             _logger = logmanager.GetLogger("PortMapper");
             _logger = logmanager.GetLogger("PortMapper");
             _appHost = appHost;
             _appHost = appHost;
             _config = config;
             _config = config;
+            _ssdp = ssdp;
         }
         }
 
 
         private string _lastConfigIdentifier;
         private string _lastConfigIdentifier;
@@ -75,10 +79,10 @@ namespace MediaBrowser.Server.Implementations.EntryPoints
         private void Start()
         private void Start()
         {
         {
             _logger.Debug("Starting NAT discovery");
             _logger.Debug("Starting NAT discovery");
-            //NatUtility.EnabledProtocols = new List<NatProtocol>
-            //{
-            //    NatProtocol.Pmp
-            //};
+            NatUtility.EnabledProtocols = new List<NatProtocol>
+            {
+                NatProtocol.Pmp
+            };
             NatUtility.DeviceFound += NatUtility_DeviceFound;
             NatUtility.DeviceFound += NatUtility_DeviceFound;
 
 
             // Mono.Nat does never rise this event. The event is there however it is useless. 
             // Mono.Nat does never rise this event. The event is there however it is useless. 
@@ -93,11 +97,23 @@ namespace MediaBrowser.Server.Implementations.EntryPoints
 
 
             _timer = new Timer(s => _createdRules = new List<string>(), null, TimeSpan.FromMinutes(5), TimeSpan.FromMinutes(5));
             _timer = new Timer(s => _createdRules = new List<string>(), null, TimeSpan.FromMinutes(5), TimeSpan.FromMinutes(5));
 
 
+            _ssdp.MessageReceived += _ssdp_MessageReceived;
+
             _lastConfigIdentifier = GetConfigIdentifier();
             _lastConfigIdentifier = GetConfigIdentifier();
 
 
             _isStarted = true;
             _isStarted = true;
         }
         }
 
 
+        void _ssdp_MessageReceived(object sender, SsdpMessageEventArgs e)
+        {
+            var endpoint = e.EndPoint as IPEndPoint;
+
+            if (endpoint != null && e.LocalIp != null)
+            {
+                NatUtility.Handle(e.LocalIp, e.Message, endpoint, NatProtocol.Upnp);
+            }
+        }
+
         void NatUtility_UnhandledException(object sender, UnhandledExceptionEventArgs e)
         void NatUtility_UnhandledException(object sender, UnhandledExceptionEventArgs e)
         {
         {
             var ex = e.ExceptionObject as Exception;
             var ex = e.ExceptionObject as Exception;
@@ -183,6 +199,8 @@ namespace MediaBrowser.Server.Implementations.EntryPoints
                 _timer = null;
                 _timer = null;
             }
             }
 
 
+            _ssdp.MessageReceived -= _ssdp_MessageReceived;
+
             try
             try
             {
             {
                 // This is not a significant improvement
                 // This is not a significant improvement

+ 1 - 2
MediaBrowser.Server.Implementations/FileOrganization/EpisodeFileOrganizer.cs

@@ -8,7 +8,6 @@ using MediaBrowser.Model.Entities;
 using MediaBrowser.Model.Extensions;
 using MediaBrowser.Model.Extensions;
 using MediaBrowser.Model.FileOrganization;
 using MediaBrowser.Model.FileOrganization;
 using MediaBrowser.Model.Logging;
 using MediaBrowser.Model.Logging;
-using MediaBrowser.Naming.IO;
 using MediaBrowser.Server.Implementations.Library;
 using MediaBrowser.Server.Implementations.Library;
 using MediaBrowser.Server.Implementations.Logging;
 using MediaBrowser.Server.Implementations.Logging;
 using System;
 using System;
@@ -60,7 +59,7 @@ namespace MediaBrowser.Server.Implementations.FileOrganization
             var namingOptions = ((LibraryManager) _libraryManager).GetNamingOptions();
             var namingOptions = ((LibraryManager) _libraryManager).GetNamingOptions();
             var resolver = new Naming.TV.EpisodeResolver(namingOptions, new PatternsLogger());
             var resolver = new Naming.TV.EpisodeResolver(namingOptions, new PatternsLogger());
 
 
-            var episodeInfo = resolver.Resolve(path, FileInfoType.File) ??
+            var episodeInfo = resolver.Resolve(path, false) ??
                 new Naming.TV.EpisodeInfo();
                 new Naming.TV.EpisodeInfo();
 
 
             var seriesName = episodeInfo.SeriesName;
             var seriesName = episodeInfo.SeriesName;

+ 4 - 4
MediaBrowser.Server.Implementations/IO/LibraryMonitor.cs

@@ -84,7 +84,7 @@ namespace MediaBrowser.Server.Implementations.IO
             // This is an arbitraty amount of time, but delay it because file system writes often trigger events after RemoveTempIgnore has been called. 
             // This is an arbitraty amount of time, but delay it because file system writes often trigger events after RemoveTempIgnore has been called. 
             // Seeing long delays in some situations, especially over the network.
             // Seeing long delays in some situations, especially over the network.
             // Seeing delays up to 40 seconds, but not going to ignore changes for that long.
             // Seeing delays up to 40 seconds, but not going to ignore changes for that long.
-            await Task.Delay(1500).ConfigureAwait(false);
+            await Task.Delay(5000).ConfigureAwait(false);
 
 
             string val;
             string val;
             _tempIgnoredPaths.TryRemove(path, out val);
             _tempIgnoredPaths.TryRemove(path, out val);
@@ -437,11 +437,11 @@ namespace MediaBrowser.Server.Implementations.IO
             {
             {
                 if (_updateTimer == null)
                 if (_updateTimer == null)
                 {
                 {
-                    _updateTimer = new Timer(TimerStopped, null, TimeSpan.FromSeconds(ConfigurationManager.Configuration.RealtimeMonitorDelay), TimeSpan.FromMilliseconds(-1));
+                    _updateTimer = new Timer(TimerStopped, null, TimeSpan.FromSeconds(ConfigurationManager.Configuration.RealtimeLibraryMonitorDelay), TimeSpan.FromMilliseconds(-1));
                 }
                 }
                 else
                 else
                 {
                 {
-                    _updateTimer.Change(TimeSpan.FromSeconds(ConfigurationManager.Configuration.RealtimeMonitorDelay), TimeSpan.FromMilliseconds(-1));
+                    _updateTimer.Change(TimeSpan.FromSeconds(ConfigurationManager.Configuration.RealtimeLibraryMonitorDelay), TimeSpan.FromMilliseconds(-1));
                 }
                 }
             }
             }
         }
         }
@@ -560,7 +560,7 @@ namespace MediaBrowser.Server.Implementations.IO
         /// <returns>Task.</returns>
         /// <returns>Task.</returns>
         private async Task ProcessPathChanges(List<string> paths)
         private async Task ProcessPathChanges(List<string> paths)
         {
         {
-            var itemsToRefresh = paths.Select(Path.GetDirectoryName)
+            var itemsToRefresh = paths
                 .Select(GetAffectedBaseItem)
                 .Select(GetAffectedBaseItem)
                 .Where(item => item != null)
                 .Where(item => item != null)
                 .Distinct()
                 .Distinct()

+ 21 - 25
MediaBrowser.Server.Implementations/Library/LibraryManager.cs

@@ -1,4 +1,5 @@
-using MediaBrowser.Common.Extensions;
+using Interfaces.IO;
+using MediaBrowser.Common.Extensions;
 using MediaBrowser.Common.IO;
 using MediaBrowser.Common.IO;
 using MediaBrowser.Common.Progress;
 using MediaBrowser.Common.Progress;
 using MediaBrowser.Common.ScheduledTasks;
 using MediaBrowser.Common.ScheduledTasks;
@@ -17,7 +18,6 @@ using MediaBrowser.Model.Entities;
 using MediaBrowser.Model.Logging;
 using MediaBrowser.Model.Logging;
 using MediaBrowser.Naming.Audio;
 using MediaBrowser.Naming.Audio;
 using MediaBrowser.Naming.Common;
 using MediaBrowser.Naming.Common;
-using MediaBrowser.Naming.IO;
 using MediaBrowser.Naming.TV;
 using MediaBrowser.Naming.TV;
 using MediaBrowser.Naming.Video;
 using MediaBrowser.Naming.Video;
 using MediaBrowser.Server.Implementations.Library.Validators;
 using MediaBrowser.Server.Implementations.Library.Validators;
@@ -1594,6 +1594,8 @@ namespace MediaBrowser.Server.Implementations.Library
                 .FirstOrDefault(i => !string.IsNullOrWhiteSpace(i));
                 .FirstOrDefault(i => !string.IsNullOrWhiteSpace(i));
         }
         }
 
 
+        private readonly TimeSpan _viewRefreshInterval = TimeSpan.FromHours(24);
+
         public async Task<UserView> GetNamedView(User user,
         public async Task<UserView> GetNamedView(User user,
             string name,
             string name,
             string viewType,
             string viewType,
@@ -1645,13 +1647,18 @@ namespace MediaBrowser.Server.Implementations.Library
 
 
             if (!refresh && item != null)
             if (!refresh && item != null)
             {
             {
-                refresh = (DateTime.UtcNow - item.DateLastSaved).TotalHours >= 24;
+                refresh = (DateTime.UtcNow - item.DateLastSaved) >= _viewRefreshInterval;
             }
             }
 
 
             if (refresh)
             if (refresh)
             {
             {
                 await item.UpdateToRepository(ItemUpdateType.MetadataImport, CancellationToken.None).ConfigureAwait(false);
                 await item.UpdateToRepository(ItemUpdateType.MetadataImport, CancellationToken.None).ConfigureAwait(false);
-                _providerManagerFactory().QueueRefresh(item.Id, new MetadataRefreshOptions());
+                _providerManagerFactory().QueueRefresh(item.Id, new MetadataRefreshOptions
+                {
+                    // Not sure why this is necessary but need to figure it out
+                    // View images are not getting utilized without this
+                    ForceSave = true
+                });
             }
             }
 
 
             return item;
             return item;
@@ -1731,7 +1738,7 @@ namespace MediaBrowser.Server.Implementations.Library
                 await item.UpdateToRepository(ItemUpdateType.MetadataEdit, cancellationToken).ConfigureAwait(false);
                 await item.UpdateToRepository(ItemUpdateType.MetadataEdit, cancellationToken).ConfigureAwait(false);
             }
             }
 
 
-            var refresh = isNew || (DateTime.UtcNow - item.DateLastSaved).TotalHours >= 24;
+            var refresh = isNew || (DateTime.UtcNow - item.DateLastSaved) >= _viewRefreshInterval;
 
 
             if (refresh)
             if (refresh)
             {
             {
@@ -1767,14 +1774,13 @@ namespace MediaBrowser.Server.Implementations.Library
             var resolver = new EpisodeResolver(GetNamingOptions(),
             var resolver = new EpisodeResolver(GetNamingOptions(),
                 new PatternsLogger());
                 new PatternsLogger());
 
 
-            var fileType = episode.VideoType == VideoType.BluRay || episode.VideoType == VideoType.Dvd || episode.VideoType == VideoType.HdDvd ?
-                FileInfoType.Directory :
-                FileInfoType.File;
+            var isFolder = episode.VideoType == VideoType.BluRay || episode.VideoType == VideoType.Dvd ||
+                           episode.VideoType == VideoType.HdDvd;
 
 
             var locationType = episode.LocationType;
             var locationType = episode.LocationType;
 
 
             var episodeInfo = locationType == LocationType.FileSystem || locationType == LocationType.Offline ?
             var episodeInfo = locationType == LocationType.FileSystem || locationType == LocationType.Offline ?
-                resolver.Resolve(episode.Path, fileType) :
+                resolver.Resolve(episode.Path, isFolder) :
                 new Naming.TV.EpisodeInfo();
                 new Naming.TV.EpisodeInfo();
 
 
             if (episodeInfo == null)
             if (episodeInfo == null)
@@ -1928,10 +1934,10 @@ namespace MediaBrowser.Server.Implementations.Library
 
 
             var videoListResolver = new VideoListResolver(GetNamingOptions(), new PatternsLogger());
             var videoListResolver = new VideoListResolver(GetNamingOptions(), new PatternsLogger());
 
 
-            var videos = videoListResolver.Resolve(fileSystemChildren.Select(i => new PortableFileInfo
+            var videos = videoListResolver.Resolve(fileSystemChildren.Select(i => new FileMetadata
             {
             {
-                FullName = i.FullName,
-                Type = GetFileType(i)
+                Id = i.FullName,
+                IsFolder = ((i.Attributes & FileAttributes.Directory) == FileAttributes.Directory)
 
 
             }).ToList());
             }).ToList());
 
 
@@ -1962,16 +1968,6 @@ namespace MediaBrowser.Server.Implementations.Library
             }).OrderBy(i => i.Path).ToList();
             }).OrderBy(i => i.Path).ToList();
         }
         }
 
 
-        private FileInfoType GetFileType(FileSystemInfo info)
-        {
-            if ((info.Attributes & FileAttributes.Directory) == FileAttributes.Directory)
-            {
-                return FileInfoType.Directory;
-            }
-
-            return FileInfoType.File;
-        }
-
         public IEnumerable<Video> FindExtras(BaseItem owner, List<FileSystemInfo> fileSystemChildren, IDirectoryService directoryService)
         public IEnumerable<Video> FindExtras(BaseItem owner, List<FileSystemInfo> fileSystemChildren, IDirectoryService directoryService)
         {
         {
             var files = fileSystemChildren.OfType<DirectoryInfo>()
             var files = fileSystemChildren.OfType<DirectoryInfo>()
@@ -1981,10 +1977,10 @@ namespace MediaBrowser.Server.Implementations.Library
 
 
             var videoListResolver = new VideoListResolver(GetNamingOptions(), new PatternsLogger());
             var videoListResolver = new VideoListResolver(GetNamingOptions(), new PatternsLogger());
 
 
-            var videos = videoListResolver.Resolve(fileSystemChildren.Select(i => new PortableFileInfo
+            var videos = videoListResolver.Resolve(fileSystemChildren.Select(i => new FileMetadata
             {
             {
-                FullName = i.FullName,
-                Type = GetFileType(i)
+                Id = i.FullName,
+                IsFolder = ((i.Attributes & FileAttributes.Directory) == FileAttributes.Directory)
 
 
             }).ToList());
             }).ToList());
 
 

Một số tệp đã không được hiển thị bởi vì quá nhiều tập tin thay đổi trong này khác