Bläddra i källkod

Merge branch 'dev' of https://github.com/MediaBrowser/MediaBrowser into dev

Conflicts:
	MediaBrowser.Server.Implementations/Localization/Server/server.json
Tavares André 10 år sedan
förälder
incheckning
48e7ca8725
97 ändrade filer med 1009 tillägg och 1145 borttagningar
  1. 1 3
      MediaBrowser.Api/Images/ImageService.cs
  2. 2 51
      MediaBrowser.Api/Library/LibraryService.cs
  3. 8 27
      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. 2 1
      MediaBrowser.Api/Playback/Progressive/AudioService.cs
  9. 2 1
      MediaBrowser.Api/Playback/Progressive/BaseProgressiveStreamingService.cs
  10. 2 1
      MediaBrowser.Api/Playback/Progressive/VideoService.cs
  11. 2 5
      MediaBrowser.Common.Implementations/MediaBrowser.Common.Implementations.csproj
  12. 13 30
      MediaBrowser.Common.Implementations/Networking/BaseNetworkManager.cs
  13. 1 1
      MediaBrowser.Common.Implementations/packages.config
  14. 8 30
      MediaBrowser.Controller/Entities/Audio/Audio.cs
  15. 0 47
      MediaBrowser.Controller/Entities/Audio/MusicAlbum.cs
  16. 0 32
      MediaBrowser.Controller/Entities/BaseItem.cs
  17. 0 23
      MediaBrowser.Controller/Entities/TV/Episode.cs
  18. 1 43
      MediaBrowser.Controller/Entities/TV/Season.cs
  19. 0 13
      MediaBrowser.Controller/Entities/TV/Series.cs
  20. 3 1
      MediaBrowser.Dlna/DlnaManager.cs
  21. 6 0
      MediaBrowser.Dlna/MediaBrowser.Dlna.csproj
  22. 8 8
      MediaBrowser.Dlna/PlayTo/Device.cs
  23. 4 1
      MediaBrowser.Dlna/PlayTo/PlayToController.cs
  24. 7 7
      MediaBrowser.Dlna/PlayTo/SsdpHttpClient.cs
  25. 76 0
      MediaBrowser.Dlna/Profiles/BubbleUpnpProfile.cs
  26. 7 0
      MediaBrowser.Dlna/Profiles/SonyBravia2010Profile.cs
  27. 7 0
      MediaBrowser.Dlna/Profiles/SonyBravia2011Profile.cs
  28. 7 0
      MediaBrowser.Dlna/Profiles/SonyBravia2012Profile.cs
  29. 7 0
      MediaBrowser.Dlna/Profiles/SonyBravia2013Profile.cs
  30. 76 0
      MediaBrowser.Dlna/Profiles/VlcProfile.cs
  31. 0 1
      MediaBrowser.Dlna/Profiles/WdtvLiveProfile.cs
  32. 29 0
      MediaBrowser.Dlna/Profiles/Xml/BubbleUPnp.xml
  33. 0 1
      MediaBrowser.Dlna/Profiles/Xml/Default.xml
  34. 0 1
      MediaBrowser.Dlna/Profiles/Xml/Denon AVR.xml
  35. 0 1
      MediaBrowser.Dlna/Profiles/Xml/DirecTV HD-DVR.xml
  36. 0 1
      MediaBrowser.Dlna/Profiles/Xml/Dish Hopper-Joey.xml
  37. 23 0
      MediaBrowser.Dlna/Profiles/Xml/Generic Device.xml
  38. 0 1
      MediaBrowser.Dlna/Profiles/Xml/LG Smart TV.xml
  39. 0 1
      MediaBrowser.Dlna/Profiles/Xml/Linksys DMA2100.xml
  40. 0 1
      MediaBrowser.Dlna/Profiles/Xml/MediaMonkey.xml
  41. 0 1
      MediaBrowser.Dlna/Profiles/Xml/Panasonic Viera.xml
  42. 0 1
      MediaBrowser.Dlna/Profiles/Xml/Popcorn Hour.xml
  43. 0 1
      MediaBrowser.Dlna/Profiles/Xml/Samsung Smart TV.xml
  44. 0 1
      MediaBrowser.Dlna/Profiles/Xml/Sony Blu-ray Player 2013.xml
  45. 0 1
      MediaBrowser.Dlna/Profiles/Xml/Sony Blu-ray Player.xml
  46. 2 2
      MediaBrowser.Dlna/Profiles/Xml/Sony Bravia (2010).xml
  47. 2 2
      MediaBrowser.Dlna/Profiles/Xml/Sony Bravia (2011).xml
  48. 2 2
      MediaBrowser.Dlna/Profiles/Xml/Sony Bravia (2012).xml
  49. 2 2
      MediaBrowser.Dlna/Profiles/Xml/Sony Bravia (2013).xml
  50. 0 1
      MediaBrowser.Dlna/Profiles/Xml/Sony PlayStation 3.xml
  51. 29 0
      MediaBrowser.Dlna/Profiles/Xml/Vlc.xml
  52. 0 1
      MediaBrowser.Dlna/Profiles/Xml/WDTV Live.xml
  53. 0 1
      MediaBrowser.Dlna/Profiles/Xml/Xbox 360.xml
  54. 0 1
      MediaBrowser.Dlna/Profiles/Xml/Xbox One.xml
  55. 0 1
      MediaBrowser.Dlna/Profiles/Xml/foobar2000.xml
  56. 4 2
      MediaBrowser.Dlna/Service/BaseControlHandler.cs
  57. 15 4
      MediaBrowser.Dlna/Ssdp/Datagram.cs
  58. 17 8
      MediaBrowser.Dlna/Ssdp/DeviceDiscovery.cs
  59. 82 26
      MediaBrowser.Dlna/Ssdp/SsdpHandler.cs
  60. 3 25
      MediaBrowser.MediaEncoding/Encoder/BaseEncoder.cs
  61. 160 136
      MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs
  62. 0 2
      MediaBrowser.MediaEncoding/Encoder/VideoEncoder.cs
  63. 2 4
      MediaBrowser.Model/Configuration/ServerConfiguration.cs
  64. 26 1
      MediaBrowser.Model/Dlna/CodecProfile.cs
  65. 2 1
      MediaBrowser.Model/Dlna/ContentFeatureBuilder.cs
  66. 0 1
      MediaBrowser.Model/Dlna/DeviceProfile.cs
  67. 6 6
      MediaBrowser.Model/Dlna/StreamBuilder.cs
  68. 14 16
      MediaBrowser.Providers/Manager/ItemImageProvider.cs
  69. 1 1
      MediaBrowser.Providers/MediaInfo/AudioImageProvider.cs
  70. 11 4
      MediaBrowser.Providers/TV/TvdbEpisodeProvider.cs
  71. 1 10
      MediaBrowser.Server.Implementations/Dto/DtoService.cs
  72. 4 4
      MediaBrowser.Server.Implementations/IO/LibraryMonitor.cs
  73. 3 3
      MediaBrowser.Server.Implementations/Library/UserManager.cs
  74. 0 1
      MediaBrowser.Server.Implementations/Localization/JavaScript/cs.json
  75. 7 2
      MediaBrowser.Server.Implementations/Localization/JavaScript/javascript.json
  76. 14 7
      MediaBrowser.Server.Implementations/Localization/Server/server.json
  77. 3 4
      MediaBrowser.Server.Implementations/MediaBrowser.Server.Implementations.csproj
  78. 56 0
      MediaBrowser.Server.Implementations/Persistence/BaseSqliteRepository.cs
  79. 0 10
      MediaBrowser.Server.Implementations/Persistence/SqliteChapterRepository.cs
  80. 21 75
      MediaBrowser.Server.Implementations/Persistence/SqliteDisplayPreferencesRepository.cs
  81. 20 62
      MediaBrowser.Server.Implementations/Persistence/SqliteFileOrganizationRepository.cs
  82. 0 10
      MediaBrowser.Server.Implementations/Persistence/SqliteItemRepository.cs
  83. 1 12
      MediaBrowser.Server.Implementations/Persistence/SqliteMediaStreamsRepository.cs
  84. 17 63
      MediaBrowser.Server.Implementations/Persistence/SqliteProviderInfoRepository.cs
  85. 0 84
      MediaBrowser.Server.Implementations/Persistence/SqliteShrinkMemoryTimer.cs
  86. 22 82
      MediaBrowser.Server.Implementations/Persistence/SqliteUserDataRepository.cs
  87. 24 75
      MediaBrowser.Server.Implementations/Persistence/SqliteUserRepository.cs
  88. 29 2
      MediaBrowser.Server.Implementations/Photos/BaseDynamicImageProvider.cs
  89. 2 1
      MediaBrowser.Server.Implementations/Photos/PhotoAlbumImageProvider.cs
  90. 1 1
      MediaBrowser.Server.Implementations/Session/SessionManager.cs
  91. 2 4
      MediaBrowser.Server.Implementations/UserViews/DynamicImageProvider.cs
  92. 2 2
      MediaBrowser.Server.Implementations/packages.config
  93. 4 4
      MediaBrowser.Server.Startup.Common/ApplicationHost.cs
  94. 15 12
      MediaBrowser.WebDashboard/Api/DashboardService.cs
  95. 57 21
      MediaBrowser.WebDashboard/Api/PackageCreator.cs
  96. 13 1
      MediaBrowser.WebDashboard/MediaBrowser.WebDashboard.csproj
  97. 1 1
      Nuget/MediaBrowser.Common.Internal.nuspec

+ 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));
 
 

+ 8 - 27
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);

+ 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)
         {
         {
         }
         }
 
 

+ 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)
         {
         {
         }
         }
 
 

+ 2 - 5
MediaBrowser.Common.Implementations/MediaBrowser.Common.Implementations.csproj

@@ -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()

+ 1 - 1
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.1" targetFramework="net45" />
   <package id="NLog" version="3.2.1" targetFramework="net45" />
-  <package id="SimpleInjector" version="2.7.0" targetFramework="net45" />
+  <package id="SimpleInjector" version="2.8.0" targetFramework="net45" />
 </packages>
 </packages>

+ 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>

+ 3 - 1
MediaBrowser.Dlna/DlnaManager.cs

@@ -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)

+ 6 - 0
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" />
@@ -204,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 - 1
MediaBrowser.Dlna/PlayTo/PlayToController.cs

@@ -768,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);
                     }
                     }
                 }
                 }

+ 7 - 7
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;
@@ -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[] { };
+        }
+    }
+}

+ 7 - 0
MediaBrowser.Dlna/Profiles/SonyBravia2010Profile.cs

@@ -47,6 +47,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 +294,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"
                         }
                         }
                     }
                     }
                 },
                 },

+ 7 - 0
MediaBrowser.Dlna/Profiles/SonyBravia2011Profile.cs

@@ -44,6 +44,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 +311,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"
                         }
                         }
                     }
                     }
                 },
                 },

+ 7 - 0
MediaBrowser.Dlna/Profiles/SonyBravia2012Profile.cs

@@ -44,6 +44,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 +251,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"
                         }
                         }
                     }
                     }
                 },
                 },

+ 7 - 0
MediaBrowser.Dlna/Profiles/SonyBravia2013Profile.cs

@@ -44,6 +44,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 +285,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
             {
             {

Filskillnaden har hållts tillbaka eftersom den är för stor
+ 29 - 0
MediaBrowser.Dlna/Profiles/Xml/BubbleUPnp.xml


+ 0 - 1
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>

+ 0 - 1
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>

+ 0 - 1
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>

+ 0 - 1
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>

Filskillnaden har hållts tillbaka eftersom den är för stor
+ 23 - 0
MediaBrowser.Dlna/Profiles/Xml/Generic Device.xml


+ 0 - 1
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>

+ 0 - 1
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>

+ 0 - 1
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>

+ 0 - 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>

+ 0 - 1
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>

+ 0 - 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>

+ 0 - 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>

+ 0 - 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>

+ 2 - 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>
@@ -79,6 +78,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">

+ 2 - 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>
@@ -82,6 +81,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">

+ 2 - 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>
@@ -67,6 +66,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">

+ 2 - 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>
@@ -72,6 +71,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>

+ 0 - 1
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>

Filskillnaden har hållts tillbaka eftersom den är för stor
+ 29 - 0
MediaBrowser.Dlna/Profiles/Xml/Vlc.xml


+ 0 - 1
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>

+ 0 - 1
MediaBrowser.Dlna/Profiles/Xml/Xbox 360.xml

@@ -15,7 +15,6 @@
   <ModelDescription>Emby</ModelDescription>
   <ModelDescription>Emby</ModelDescription>
   <ModelNumber>12.0</ModelNumber>
   <ModelNumber>12.0</ModelNumber>
   <ModelUrl>http://www.microsoft.com/</ModelUrl>
   <ModelUrl>http://www.microsoft.com/</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>

+ 0 - 1
MediaBrowser.Dlna/Profiles/Xml/Xbox One.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>

+ 0 - 1
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>

+ 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);
                 }
                 }

+ 15 - 4
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;
@@ -37,8 +39,13 @@ namespace MediaBrowser.Dlna.Ssdp
                     {
                     {
                         client.Bind(FromEndPoint);
                         client.Bind(FromEndPoint);
                     }
                     }
-                    catch
+                    catch (Exception ex)
                     {
                     {
+                        if (EnableDebugLogging)
+                        {
+                            _logger.ErrorException("Error binding datagram socket", ex);
+                        }
+                        
                         if (!IgnoreBindFailure) throw;
                         if (!IgnoreBindFailure) throw;
                     }
                     }
                 }
                 }
@@ -51,7 +58,7 @@ namespace MediaBrowser.Dlna.Ssdp
                     }
                     }
                     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());
                         }
                         }
@@ -62,8 +69,12 @@ namespace MediaBrowser.Dlna.Ssdp
                         {
                         {
                             client.Close();
                             client.Close();
                         }
                         }
-                        catch (Exception)
+                        catch (Exception ex)
                         {
                         {
+                            if (EnableDebugLogging)
+                            {
+                                _logger.ErrorException("Error closing datagram socket", ex);
+                            }
                         }
                         }
                     }
                     }
                 }, null);
                 }, null);

+ 17 - 8
MediaBrowser.Dlna/Ssdp/DeviceDiscovery.cs

@@ -1,5 +1,4 @@
 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.Controller.Dlna;
@@ -143,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);
+                            }
                         }
                         }
                     }
                     }
 
 
@@ -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) ||

+ 82 - 26
MediaBrowser.Dlna/Ssdp/SsdpHandler.cs

@@ -67,7 +67,7 @@ namespace MediaBrowser.Dlna.Ssdp
             }
             }
 
 
             return String.Format(
             return String.Format(
-              "{0}{1}/{2}.{3} UPnP/1.0 DLNADOC/1.5 MediaBrowser/{4}",
+              "{0}{1}/{2}.{3} UPnP/1.0 DLNADOC/1.5 Emby/{4}",
               pstring,
               pstring,
               IntPtr.Size * 8,
               IntPtr.Size * 8,
               os.Version.Major,
               os.Version.Major,
@@ -88,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);
@@ -166,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)
                 {
                 {
@@ -212,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";
 
 
@@ -224,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";
@@ -238,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());
                     }
                     }
@@ -316,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));
                 }
                 }
@@ -324,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());
@@ -345,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;
@@ -399,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";
 
 
@@ -424,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);
             }
             }
@@ -457,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);
@@ -468,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)
             {
             {

+ 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)

+ 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;

+ 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"

+ 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);

+ 2 - 1
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
@@ -164,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
             {
             {

+ 0 - 1
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; }

+ 6 - 6
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)
                         {
                         {
@@ -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)
                     {
                     {
@@ -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;

+ 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)
             {
             {

+ 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()

+ 3 - 3
MediaBrowser.Server.Implementations/Library/UserManager.cs

@@ -281,10 +281,10 @@ namespace MediaBrowser.Server.Implementations.Library
 
 
                 if (newValue >= maxCount)
                 if (newValue >= maxCount)
                 {
                 {
-                    _logger.Debug("Disabling user {0} due to {1} unsuccessful login attempts.", user.Name, newValue.ToString(CultureInfo.InvariantCulture));
-                    user.Policy.IsDisabled = true;
+                    //_logger.Debug("Disabling user {0} due to {1} unsuccessful login attempts.", user.Name, newValue.ToString(CultureInfo.InvariantCulture));
+                    //user.Policy.IsDisabled = true;
 
 
-                    fireLockout = true;
+                    //fireLockout = true;
                 }
                 }
 
 
                 await UpdateUserPolicy(user, user.Policy, false).ConfigureAwait(false);
                 await UpdateUserPolicy(user, user.Policy, false).ConfigureAwait(false);

+ 0 - 1
MediaBrowser.Server.Implementations/Localization/JavaScript/cs.json

@@ -387,7 +387,6 @@
     "ButtonSignOut": "Sign Out",
     "ButtonSignOut": "Sign Out",
     "ButtonMyProfile": "My Profile",
     "ButtonMyProfile": "My Profile",
     "ButtonMyPreferences": "My Preferences",
     "ButtonMyPreferences": "My Preferences",
-    "MessageBrowserDoesNotSupportWebSockets": "This browser does not support web sockets. For a better experience, try a newer browser such as Chrome, Firefox, IE10+, Safari (iOS) or Opera.",
     "LabelInstallingPackage": "Installing {0}",
     "LabelInstallingPackage": "Installing {0}",
     "LabelPackageInstallCompleted": "{0} installation completed.",
     "LabelPackageInstallCompleted": "{0} installation completed.",
     "LabelPackageInstallFailed": "{0} installation failed.",
     "LabelPackageInstallFailed": "{0} installation failed.",

+ 7 - 2
MediaBrowser.Server.Implementations/Localization/JavaScript/javascript.json

@@ -440,7 +440,7 @@
     "HeaderVideo": "Video",
     "HeaderVideo": "Video",
     "HeaderRuntime": "Runtime",
     "HeaderRuntime": "Runtime",
     "HeaderCommunityRating": "Community rating",
     "HeaderCommunityRating": "Community rating",
-    "HeaderPasswordReset":  "Password Reset",
+    "HeaderPasswordReset": "Password Reset",
     "HeaderParentalRating": "Parental rating",
     "HeaderParentalRating": "Parental rating",
     "HeaderReleaseDate": "Release date",
     "HeaderReleaseDate": "Release date",
     "HeaderDateAdded": "Date added",
     "HeaderDateAdded": "Date added",
@@ -766,5 +766,10 @@
     "SyncJobItemStatusRemovedFromDevice": "Removed from device",
     "SyncJobItemStatusRemovedFromDevice": "Removed from device",
     "SyncJobItemStatusCancelled": "Cancelled",
     "SyncJobItemStatusCancelled": "Cancelled",
     "LabelProfile": "Profile:",
     "LabelProfile": "Profile:",
-    "LabelBitrateMbps": "Bitrate (Mbps):"
+    "LabelBitrateMbps": "Bitrate (Mbps):",
+    "EmbyIntroDownloadMessage": "To download and install Emby Server visit {0}.",
+    "ButtonNewServer": "New Server",
+    "ButtonSignInWithConnect": "Sign in with Emby Connect",
+    "HeaderNewServer": "New Server",
+    "MyDevice":  "My Device"
 }
 }

+ 14 - 7
MediaBrowser.Server.Implementations/Localization/Server/server.json

@@ -882,7 +882,7 @@
     "MessageNoSubtitleSearchResultsFound": "No search results founds.",
     "MessageNoSubtitleSearchResultsFound": "No search results founds.",
     "TabDisplay": "Display",
     "TabDisplay": "Display",
     "TabLanguages": "Languages",
     "TabLanguages": "Languages",
-    "TabWebClient": "Web Client",
+    "TabAppSettings": "App Settings",
     "LabelEnableThemeSongs": "Enable theme songs",
     "LabelEnableThemeSongs": "Enable theme songs",
     "LabelEnableBackdrops": "Enable backdrops",
     "LabelEnableBackdrops": "Enable backdrops",
     "LabelEnableThemeSongsHelp": "If enabled, theme songs will be played in the background while browsing the library.",
     "LabelEnableThemeSongsHelp": "If enabled, theme songs will be played in the background while browsing the library.",
@@ -1436,10 +1436,17 @@
     "LabelSelectViewStyles": "Enable enhanced presentations for:",
     "LabelSelectViewStyles": "Enable enhanced presentations for:",
     "LabelSelectViewStylesHelp": "If enabled, views will be built with metadata to offer categories such as Suggestions, Latest, Genres, and more. If disabled, they'll be displayed with simple folders.",
     "LabelSelectViewStylesHelp": "If enabled, views will be built with metadata to offer categories such as Suggestions, Latest, Genres, and more. If disabled, they'll be displayed with simple folders.",
     "TabPhotos": "Photos",
     "TabPhotos": "Photos",
-	"TabVideos": "Videos",
-	"OptionReportList": "List View",
-    "OptionReportStatistics": "Statistics",
-    "OptionReportGrouping": "Grouping",
-    "OptionReportExport": "Report Export",
-    "OptionReportColumns": "Report Columns"
+    "TabVideos": "Videos",
+    "HeaderWelcomeToEmby": "Welcome to Emby",
+    "EmbyIntroMessage": "With Emby you can easily stream videos, music and photos to smart phones, tablets and other devices from your Emby Server.",
+    "ButtonSkip": "Skip",
+    "TextConnectToServerManually": "Connect to server manually",
+    "ButtonSignInWithConnect": "Sign in with Emby Connect",
+    "ButtonConnect": "Connect",
+    "LabelServerHost": "Host:",
+    "LabelServerHostHelp": "192.168.1.100 or https://myserver.com",
+    "LabelServerPort": "Port:",
+    "HeaderNewServer": "New Server",
+    "ButtonChangeServer": "Change Server",
+    "HeaderConnectToServer": "Connect to Server"
 }
 }

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

@@ -48,9 +48,8 @@
     <Reference Include="Interfaces.IO">
     <Reference Include="Interfaces.IO">
       <HintPath>..\packages\Interfaces.IO.1.0.0.5\lib\portable-net45+sl4+wp71+win8+wpa81\Interfaces.IO.dll</HintPath>
       <HintPath>..\packages\Interfaces.IO.1.0.0.5\lib\portable-net45+sl4+wp71+win8+wpa81\Interfaces.IO.dll</HintPath>
     </Reference>
     </Reference>
-    <Reference Include="MediaBrowser.Naming, Version=1.0.5509.27636, Culture=neutral, processorArchitecture=MSIL">
-      <SpecificVersion>False</SpecificVersion>
-      <HintPath>..\packages\MediaBrowser.Naming.1.0.0.34\lib\portable-net45+sl4+wp71+win8+wpa81\MediaBrowser.Naming.dll</HintPath>
+    <Reference Include="MediaBrowser.Naming">
+      <HintPath>..\packages\MediaBrowser.Naming.1.0.0.35\lib\portable-net45+sl4+wp71+win8+wpa81\MediaBrowser.Naming.dll</HintPath>
     </Reference>
     </Reference>
     <Reference Include="Mono.Nat, Version=1.2.24.0, Culture=neutral, processorArchitecture=MSIL">
     <Reference Include="Mono.Nat, Version=1.2.24.0, Culture=neutral, processorArchitecture=MSIL">
       <SpecificVersion>False</SpecificVersion>
       <SpecificVersion>False</SpecificVersion>
@@ -226,6 +225,7 @@
     <Compile Include="Localization\LocalizationManager.cs" />
     <Compile Include="Localization\LocalizationManager.cs" />
     <Compile Include="Logging\PatternsLogger.cs" />
     <Compile Include="Logging\PatternsLogger.cs" />
     <Compile Include="MediaEncoder\EncodingManager.cs" />
     <Compile Include="MediaEncoder\EncodingManager.cs" />
+    <Compile Include="Persistence\BaseSqliteRepository.cs" />
     <Compile Include="Sorting\StartDateComparer.cs" />
     <Compile Include="Sorting\StartDateComparer.cs" />
     <Compile Include="Sync\SyncHelper.cs" />
     <Compile Include="Sync\SyncHelper.cs" />
     <Compile Include="Sync\SyncJobOptions.cs" />
     <Compile Include="Sync\SyncJobOptions.cs" />
@@ -242,7 +242,6 @@
     <Compile Include="Persistence\SqliteMediaStreamsRepository.cs" />
     <Compile Include="Persistence\SqliteMediaStreamsRepository.cs" />
     <Compile Include="Notifications\SqliteNotificationsRepository.cs" />
     <Compile Include="Notifications\SqliteNotificationsRepository.cs" />
     <Compile Include="Persistence\SqliteProviderInfoRepository.cs" />
     <Compile Include="Persistence\SqliteProviderInfoRepository.cs" />
-    <Compile Include="Persistence\SqliteShrinkMemoryTimer.cs" />
     <Compile Include="Persistence\TypeMapper.cs" />
     <Compile Include="Persistence\TypeMapper.cs" />
     <Compile Include="Photos\BaseDynamicImageProvider.cs" />
     <Compile Include="Photos\BaseDynamicImageProvider.cs" />
     <Compile Include="Playlists\ManualPlaylistsFolder.cs" />
     <Compile Include="Playlists\ManualPlaylistsFolder.cs" />

+ 56 - 0
MediaBrowser.Server.Implementations/Persistence/BaseSqliteRepository.cs

@@ -0,0 +1,56 @@
+using MediaBrowser.Model.Logging;
+using System;
+using System.Threading;
+
+namespace MediaBrowser.Server.Implementations.Persistence
+{
+    public abstract class BaseSqliteRepository : IDisposable
+    {
+        protected readonly SemaphoreSlim WriteLock = new SemaphoreSlim(1, 1);
+        protected ILogger Logger;
+
+        protected BaseSqliteRepository(ILogManager logManager)
+        {
+            Logger = logManager.GetLogger(GetType().Name);
+        }
+
+        public void Dispose()
+        {
+            Dispose(true);
+            GC.SuppressFinalize(this);
+        }
+
+        private readonly object _disposeLock = new object();
+
+        /// <summary>
+        /// Releases unmanaged and - optionally - managed resources.
+        /// </summary>
+        /// <param name="dispose"><c>true</c> to release both managed and unmanaged resources; <c>false</c> to release only unmanaged resources.</param>
+        protected virtual void Dispose(bool dispose)
+        {
+            if (dispose)
+            {
+                try
+                {
+                    lock (_disposeLock)
+                    {
+                        WriteLock.Wait();
+
+                        CloseConnection();
+                    }
+                }
+                catch (Exception ex)
+                {
+                    Logger.ErrorException("Error disposing database", ex);
+                }
+            }
+        }
+
+        protected virtual void DisposeInternal()
+        {
+
+        }
+
+        protected abstract void CloseConnection();
+    }
+}

+ 0 - 10
MediaBrowser.Server.Implementations/Persistence/SqliteChapterRepository.cs

@@ -32,8 +32,6 @@ namespace MediaBrowser.Server.Implementations.Persistence
             _logger = logManager.GetLogger(GetType().Name);
             _logger = logManager.GetLogger(GetType().Name);
         }
         }
 
 
-        private SqliteShrinkMemoryTimer _shrinkMemoryTimer;
-
         /// <summary>
         /// <summary>
         /// Opens the connection to the database
         /// Opens the connection to the database
         /// </summary>
         /// </summary>
@@ -54,8 +52,6 @@ namespace MediaBrowser.Server.Implementations.Persistence
             _connection.RunQueries(queries, _logger);
             _connection.RunQueries(queries, _logger);
 
 
             PrepareStatements();
             PrepareStatements();
-
-            _shrinkMemoryTimer = new SqliteShrinkMemoryTimer(_connection, _writeLock, _logger);
         }
         }
 
 
         /// <summary>
         /// <summary>
@@ -286,12 +282,6 @@ namespace MediaBrowser.Server.Implementations.Persistence
                 {
                 {
                     lock (_disposeLock)
                     lock (_disposeLock)
                     {
                     {
-                        if (_shrinkMemoryTimer != null)
-                        {
-                            _shrinkMemoryTimer.Dispose();
-                            _shrinkMemoryTimer = null;
-                        }
-
                         if (_connection != null)
                         if (_connection != null)
                         {
                         {
                             if (_connection.IsOpen())
                             if (_connection.IsOpen())

+ 21 - 75
MediaBrowser.Server.Implementations/Persistence/SqliteDisplayPreferencesRepository.cs

@@ -16,11 +16,15 @@ namespace MediaBrowser.Server.Implementations.Persistence
     /// <summary>
     /// <summary>
     /// Class SQLiteDisplayPreferencesRepository
     /// Class SQLiteDisplayPreferencesRepository
     /// </summary>
     /// </summary>
-    public class SqliteDisplayPreferencesRepository : IDisplayPreferencesRepository
+    public class SqliteDisplayPreferencesRepository : BaseSqliteRepository, IDisplayPreferencesRepository
     {
     {
         private IDbConnection _connection;
         private IDbConnection _connection;
 
 
-        private readonly ILogger _logger;
+        public SqliteDisplayPreferencesRepository(ILogManager logManager, IJsonSerializer jsonSerializer, IApplicationPaths appPaths) : base(logManager)
+        {
+            _jsonSerializer = jsonSerializer;
+            _appPaths = appPaths;
+        }
 
 
         /// <summary>
         /// <summary>
         /// Gets the name of the repository
         /// Gets the name of the repository
@@ -44,36 +48,6 @@ namespace MediaBrowser.Server.Implementations.Persistence
         /// </summary>
         /// </summary>
         private readonly IApplicationPaths _appPaths;
         private readonly IApplicationPaths _appPaths;
 
 
-        private readonly SemaphoreSlim _writeLock = new SemaphoreSlim(1, 1);
-
-        /// <summary>
-        /// Initializes a new instance of the <see cref="SqliteDisplayPreferencesRepository" /> class.
-        /// </summary>
-        /// <param name="appPaths">The app paths.</param>
-        /// <param name="jsonSerializer">The json serializer.</param>
-        /// <param name="logManager">The log manager.</param>
-        /// <exception cref="System.ArgumentNullException">
-        /// jsonSerializer
-        /// or
-        /// appPaths
-        /// </exception>
-        public SqliteDisplayPreferencesRepository(IApplicationPaths appPaths, IJsonSerializer jsonSerializer, ILogManager logManager)
-        {
-            if (jsonSerializer == null)
-            {
-                throw new ArgumentNullException("jsonSerializer");
-            }
-            if (appPaths == null)
-            {
-                throw new ArgumentNullException("appPaths");
-            }
-
-            _jsonSerializer = jsonSerializer;
-            _appPaths = appPaths;
-
-            _logger = logManager.GetLogger(GetType().Name);
-        }
-
         /// <summary>
         /// <summary>
         /// Opens the connection to the database
         /// Opens the connection to the database
         /// </summary>
         /// </summary>
@@ -82,7 +56,7 @@ namespace MediaBrowser.Server.Implementations.Persistence
         {
         {
             var dbFile = Path.Combine(_appPaths.DataPath, "displaypreferences.db");
             var dbFile = Path.Combine(_appPaths.DataPath, "displaypreferences.db");
 
 
-            _connection = await SqliteExtensions.ConnectToDb(dbFile, _logger).ConfigureAwait(false);
+            _connection = await SqliteExtensions.ConnectToDb(dbFile, Logger).ConfigureAwait(false);
 
 
             string[] queries = {
             string[] queries = {
 
 
@@ -95,7 +69,7 @@ namespace MediaBrowser.Server.Implementations.Persistence
                                 "pragma shrink_memory"
                                 "pragma shrink_memory"
                                };
                                };
 
 
-            _connection.RunQueries(queries, _logger);
+            _connection.RunQueries(queries, Logger);
         }
         }
 
 
         /// <summary>
         /// <summary>
@@ -122,7 +96,7 @@ namespace MediaBrowser.Server.Implementations.Persistence
 
 
             var serialized = _jsonSerializer.SerializeToBytes(displayPreferences);
             var serialized = _jsonSerializer.SerializeToBytes(displayPreferences);
 
 
-            await _writeLock.WaitAsync(cancellationToken).ConfigureAwait(false);
+            await WriteLock.WaitAsync(cancellationToken).ConfigureAwait(false);
 
 
             IDbTransaction transaction = null;
             IDbTransaction transaction = null;
 
 
@@ -157,7 +131,7 @@ namespace MediaBrowser.Server.Implementations.Persistence
             }
             }
             catch (Exception e)
             catch (Exception e)
             {
             {
-                _logger.ErrorException("Failed to save display preferences:", e);
+                Logger.ErrorException("Failed to save display preferences:", e);
 
 
                 if (transaction != null)
                 if (transaction != null)
                 {
                 {
@@ -173,7 +147,7 @@ namespace MediaBrowser.Server.Implementations.Persistence
                     transaction.Dispose();
                     transaction.Dispose();
                 }
                 }
 
 
-                _writeLock.Release();
+                WriteLock.Release();
             }
             }
         }
         }
 
 
@@ -194,7 +168,7 @@ namespace MediaBrowser.Server.Implementations.Persistence
 
 
             cancellationToken.ThrowIfCancellationRequested();
             cancellationToken.ThrowIfCancellationRequested();
 
 
-            await _writeLock.WaitAsync(cancellationToken).ConfigureAwait(false);
+            await WriteLock.WaitAsync(cancellationToken).ConfigureAwait(false);
 
 
             IDbTransaction transaction = null;
             IDbTransaction transaction = null;
 
 
@@ -235,7 +209,7 @@ namespace MediaBrowser.Server.Implementations.Persistence
             }
             }
             catch (Exception e)
             catch (Exception e)
             {
             {
-                _logger.ErrorException("Failed to save display preferences:", e);
+                Logger.ErrorException("Failed to save display preferences:", e);
 
 
                 if (transaction != null)
                 if (transaction != null)
                 {
                 {
@@ -251,7 +225,7 @@ namespace MediaBrowser.Server.Implementations.Persistence
                     transaction.Dispose();
                     transaction.Dispose();
                 }
                 }
 
 
-                _writeLock.Release();
+                WriteLock.Release();
             }
             }
         }
         }
 
 
@@ -322,45 +296,17 @@ namespace MediaBrowser.Server.Implementations.Persistence
             }
             }
         }
         }
 
 
-        /// <summary>
-        /// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources.
-        /// </summary>
-        public void Dispose()
+        protected override void CloseConnection()
         {
         {
-            Dispose(true);
-            GC.SuppressFinalize(this);
-        }
-
-        private readonly object _disposeLock = new object();
-
-        /// <summary>
-        /// Releases unmanaged and - optionally - managed resources.
-        /// </summary>
-        /// <param name="dispose"><c>true</c> to release both managed and unmanaged resources; <c>false</c> to release only unmanaged resources.</param>
-        protected virtual void Dispose(bool dispose)
-        {
-            if (dispose)
+            if (_connection != null)
             {
             {
-                try
+                if (_connection.IsOpen())
                 {
                 {
-                    lock (_disposeLock)
-                    {
-                        if (_connection != null)
-                        {
-                            if (_connection.IsOpen())
-                            {
-                                _connection.Close();
-                            }
-
-                            _connection.Dispose();
-                            _connection = null;
-                        }
-                    }
-                }
-                catch (Exception ex)
-                {
-                    _logger.ErrorException("Error disposing database", ex);
+                    _connection.Close();
                 }
                 }
+
+                _connection.Dispose();
+                _connection = null;
             }
             }
         }
         }
     }
     }

+ 20 - 62
MediaBrowser.Server.Implementations/Persistence/SqliteFileOrganizationRepository.cs

@@ -14,14 +14,10 @@ using System.Threading.Tasks;
 
 
 namespace MediaBrowser.Server.Implementations.Persistence
 namespace MediaBrowser.Server.Implementations.Persistence
 {
 {
-    public class SqliteFileOrganizationRepository : IFileOrganizationRepository, IDisposable
+    public class SqliteFileOrganizationRepository : BaseSqliteRepository, IFileOrganizationRepository, IDisposable
     {
     {
         private IDbConnection _connection;
         private IDbConnection _connection;
 
 
-        private readonly ILogger _logger;
-
-        private readonly SemaphoreSlim _writeLock = new SemaphoreSlim(1, 1);
-        private SqliteShrinkMemoryTimer _shrinkMemoryTimer;
         private readonly IServerApplicationPaths _appPaths;
         private readonly IServerApplicationPaths _appPaths;
 
 
         private readonly CultureInfo _usCulture = new CultureInfo("en-US");
         private readonly CultureInfo _usCulture = new CultureInfo("en-US");
@@ -30,11 +26,9 @@ namespace MediaBrowser.Server.Implementations.Persistence
         private IDbCommand _deleteResultCommand;
         private IDbCommand _deleteResultCommand;
         private IDbCommand _deleteAllCommand;
         private IDbCommand _deleteAllCommand;
 
 
-        public SqliteFileOrganizationRepository(ILogManager logManager, IServerApplicationPaths appPaths)
+        public SqliteFileOrganizationRepository(ILogManager logManager, IServerApplicationPaths appPaths) : base(logManager)
         {
         {
             _appPaths = appPaths;
             _appPaths = appPaths;
-
-            _logger = logManager.GetLogger(GetType().Name);
         }
         }
 
 
         /// <summary>
         /// <summary>
@@ -45,7 +39,7 @@ namespace MediaBrowser.Server.Implementations.Persistence
         {
         {
             var dbFile = Path.Combine(_appPaths.DataPath, "fileorganization.db");
             var dbFile = Path.Combine(_appPaths.DataPath, "fileorganization.db");
 
 
-            _connection = await SqliteExtensions.ConnectToDb(dbFile, _logger).ConfigureAwait(false);
+            _connection = await SqliteExtensions.ConnectToDb(dbFile, Logger).ConfigureAwait(false);
 
 
             string[] queries = {
             string[] queries = {
 
 
@@ -58,11 +52,9 @@ namespace MediaBrowser.Server.Implementations.Persistence
                                 "pragma shrink_memory"
                                 "pragma shrink_memory"
                                };
                                };
 
 
-            _connection.RunQueries(queries, _logger);
+            _connection.RunQueries(queries, Logger);
 
 
             PrepareStatements();
             PrepareStatements();
-
-            _shrinkMemoryTimer = new SqliteShrinkMemoryTimer(_connection, _writeLock, _logger);
         }
         }
 
 
         private void PrepareStatements()
         private void PrepareStatements()
@@ -103,7 +95,7 @@ namespace MediaBrowser.Server.Implementations.Persistence
 
 
             cancellationToken.ThrowIfCancellationRequested();
             cancellationToken.ThrowIfCancellationRequested();
 
 
-            await _writeLock.WaitAsync(cancellationToken).ConfigureAwait(false);
+            await WriteLock.WaitAsync(cancellationToken).ConfigureAwait(false);
 
 
             IDbTransaction transaction = null;
             IDbTransaction transaction = null;
 
 
@@ -145,7 +137,7 @@ namespace MediaBrowser.Server.Implementations.Persistence
             }
             }
             catch (Exception e)
             catch (Exception e)
             {
             {
-                _logger.ErrorException("Failed to save FileOrganizationResult:", e);
+                Logger.ErrorException("Failed to save FileOrganizationResult:", e);
 
 
                 if (transaction != null)
                 if (transaction != null)
                 {
                 {
@@ -161,7 +153,7 @@ namespace MediaBrowser.Server.Implementations.Persistence
                     transaction.Dispose();
                     transaction.Dispose();
                 }
                 }
 
 
-                _writeLock.Release();
+                WriteLock.Release();
             }
             }
         }
         }
 
 
@@ -172,7 +164,7 @@ namespace MediaBrowser.Server.Implementations.Persistence
                 throw new ArgumentNullException("id");
                 throw new ArgumentNullException("id");
             }
             }
 
 
-            await _writeLock.WaitAsync().ConfigureAwait(false);
+            await WriteLock.WaitAsync().ConfigureAwait(false);
 
 
             IDbTransaction transaction = null;
             IDbTransaction transaction = null;
 
 
@@ -199,7 +191,7 @@ namespace MediaBrowser.Server.Implementations.Persistence
             }
             }
             catch (Exception e)
             catch (Exception e)
             {
             {
-                _logger.ErrorException("Failed to delete FileOrganizationResult:", e);
+                Logger.ErrorException("Failed to delete FileOrganizationResult:", e);
 
 
                 if (transaction != null)
                 if (transaction != null)
                 {
                 {
@@ -215,13 +207,13 @@ namespace MediaBrowser.Server.Implementations.Persistence
                     transaction.Dispose();
                     transaction.Dispose();
                 }
                 }
 
 
-                _writeLock.Release();
+                WriteLock.Release();
             }
             }
         }
         }
 
 
         public async Task DeleteAll()
         public async Task DeleteAll()
         {
         {
-            await _writeLock.WaitAsync().ConfigureAwait(false);
+            await WriteLock.WaitAsync().ConfigureAwait(false);
 
 
             IDbTransaction transaction = null;
             IDbTransaction transaction = null;
 
 
@@ -246,7 +238,7 @@ namespace MediaBrowser.Server.Implementations.Persistence
             }
             }
             catch (Exception e)
             catch (Exception e)
             {
             {
-                _logger.ErrorException("Failed to delete results", e);
+                Logger.ErrorException("Failed to delete results", e);
 
 
                 if (transaction != null)
                 if (transaction != null)
                 {
                 {
@@ -262,7 +254,7 @@ namespace MediaBrowser.Server.Implementations.Persistence
                     transaction.Dispose();
                     transaction.Dispose();
                 }
                 }
 
 
-                _writeLock.Release();
+                WriteLock.Release();
             }
             }
         }
         }
         
         
@@ -423,51 +415,17 @@ namespace MediaBrowser.Server.Implementations.Persistence
             return result;
             return result;
         }
         }
 
 
-        /// <summary>
-        /// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources.
-        /// </summary>
-        public void Dispose()
-        {
-            Dispose(true);
-            GC.SuppressFinalize(this);
-        }
-
-        private readonly object _disposeLock = new object();
-
-        /// <summary>
-        /// Releases unmanaged and - optionally - managed resources.
-        /// </summary>
-        /// <param name="dispose"><c>true</c> to release both managed and unmanaged resources; <c>false</c> to release only unmanaged resources.</param>
-        protected virtual void Dispose(bool dispose)
+        protected override void CloseConnection()
         {
         {
-            if (dispose)
+            if (_connection != null)
             {
             {
-                try
-                {
-                    lock (_disposeLock)
-                    {
-                        if (_shrinkMemoryTimer != null)
-                        {
-                            _shrinkMemoryTimer.Dispose();
-                            _shrinkMemoryTimer = null;
-                        }
-
-                        if (_connection != null)
-                        {
-                            if (_connection.IsOpen())
-                            {
-                                _connection.Close();
-                            }
-
-                            _connection.Dispose();
-                            _connection = null;
-                        }
-                    }
-                }
-                catch (Exception ex)
+                if (_connection.IsOpen())
                 {
                 {
-                    _logger.ErrorException("Error disposing database", ex);
+                    _connection.Close();
                 }
                 }
+
+                _connection.Dispose();
+                _connection = null;
             }
             }
         }
         }
     }
     }

+ 0 - 10
MediaBrowser.Server.Implementations/Persistence/SqliteItemRepository.cs

@@ -130,12 +130,8 @@ namespace MediaBrowser.Server.Implementations.Persistence
 
 
             _mediaStreamsRepository.Initialize();
             _mediaStreamsRepository.Initialize();
             _chapterRepository.Initialize();
             _chapterRepository.Initialize();
-
-            _shrinkMemoryTimer = new SqliteShrinkMemoryTimer(_connection, _writeLock, _logger);
         }
         }
 
 
-        private SqliteShrinkMemoryTimer _shrinkMemoryTimer;
-
         /// <summary>
         /// <summary>
         /// The _write lock
         /// The _write lock
         /// </summary>
         /// </summary>
@@ -430,12 +426,6 @@ namespace MediaBrowser.Server.Implementations.Persistence
                 {
                 {
                     lock (_disposeLock)
                     lock (_disposeLock)
                     {
                     {
-                        if (_shrinkMemoryTimer != null)
-                        {
-                            _shrinkMemoryTimer.Dispose();
-                            _shrinkMemoryTimer = null;
-                        }
-
                         _writeLock.Wait();
                         _writeLock.Wait();
 
 
                         if (_connection != null)
                         if (_connection != null)

+ 1 - 12
MediaBrowser.Server.Implementations/Persistence/SqliteMediaStreamsRepository.cs

@@ -1,5 +1,4 @@
-using System.Globalization;
-using MediaBrowser.Controller.Persistence;
+using MediaBrowser.Controller.Persistence;
 using MediaBrowser.Model.Entities;
 using MediaBrowser.Model.Entities;
 using MediaBrowser.Model.Logging;
 using MediaBrowser.Model.Logging;
 using System;
 using System;
@@ -21,8 +20,6 @@ namespace MediaBrowser.Server.Implementations.Persistence
         private IDbCommand _deleteStreamsCommand;
         private IDbCommand _deleteStreamsCommand;
         private IDbCommand _saveStreamCommand;
         private IDbCommand _saveStreamCommand;
 
 
-        private SqliteShrinkMemoryTimer _shrinkMemoryTimer;
-
         public SqliteMediaStreamsRepository(IDbConnection connection, ILogManager logManager)
         public SqliteMediaStreamsRepository(IDbConnection connection, ILogManager logManager)
         {
         {
             _connection = connection;
             _connection = connection;
@@ -64,8 +61,6 @@ namespace MediaBrowser.Server.Implementations.Persistence
             AddRefFramesCommand();
             AddRefFramesCommand();
 
 
             PrepareStatements();
             PrepareStatements();
-
-            _shrinkMemoryTimer = new SqliteShrinkMemoryTimer(_connection, _writeLock, _logger);
         }
         }
 
 
         private void AddPixelFormatColumnCommand()
         private void AddPixelFormatColumnCommand()
@@ -563,12 +558,6 @@ namespace MediaBrowser.Server.Implementations.Persistence
                 {
                 {
                     lock (_disposeLock)
                     lock (_disposeLock)
                     {
                     {
-                        if (_shrinkMemoryTimer != null)
-                        {
-                            _shrinkMemoryTimer.Dispose();
-                            _shrinkMemoryTimer = null;
-                        }
-
                         if (_connection != null)
                         if (_connection != null)
                         {
                         {
                             if (_connection.IsOpen())
                             if (_connection.IsOpen())

+ 17 - 63
MediaBrowser.Server.Implementations/Persistence/SqliteProviderInfoRepository.cs

@@ -1,33 +1,28 @@
-using System.Text;
-using MediaBrowser.Common.Configuration;
+using MediaBrowser.Common.Configuration;
 using MediaBrowser.Controller.Providers;
 using MediaBrowser.Controller.Providers;
 using MediaBrowser.Model.Logging;
 using MediaBrowser.Model.Logging;
 using System;
 using System;
 using System.Data;
 using System.Data;
 using System.IO;
 using System.IO;
 using System.Linq;
 using System.Linq;
+using System.Text;
 using System.Threading;
 using System.Threading;
 using System.Threading.Tasks;
 using System.Threading.Tasks;
 
 
 namespace MediaBrowser.Server.Implementations.Persistence
 namespace MediaBrowser.Server.Implementations.Persistence
 {
 {
-    public class SqliteProviderInfoRepository : IProviderRepository
+    public class SqliteProviderInfoRepository : BaseSqliteRepository, IProviderRepository
     {
     {
         private IDbConnection _connection;
         private IDbConnection _connection;
 
 
-        private readonly ILogger _logger;
-
         private IDbCommand _saveStatusCommand;
         private IDbCommand _saveStatusCommand;
         private readonly IApplicationPaths _appPaths;
         private readonly IApplicationPaths _appPaths;
 
 
-        public SqliteProviderInfoRepository(IApplicationPaths appPaths, ILogManager logManager)
+        public SqliteProviderInfoRepository(ILogManager logManager, IApplicationPaths appPaths) : base(logManager)
         {
         {
             _appPaths = appPaths;
             _appPaths = appPaths;
-            _logger = logManager.GetLogger(GetType().Name);
         }
         }
 
 
-        private SqliteShrinkMemoryTimer _shrinkMemoryTimer;
-
         /// <summary>
         /// <summary>
         /// Gets the name of the repository
         /// Gets the name of the repository
         /// </summary>
         /// </summary>
@@ -48,7 +43,7 @@ namespace MediaBrowser.Server.Implementations.Persistence
         {
         {
             var dbFile = Path.Combine(_appPaths.DataPath, "refreshinfo.db");
             var dbFile = Path.Combine(_appPaths.DataPath, "refreshinfo.db");
 
 
-            _connection = await SqliteExtensions.ConnectToDb(dbFile, _logger).ConfigureAwait(false);
+            _connection = await SqliteExtensions.ConnectToDb(dbFile, Logger).ConfigureAwait(false);
 
 
             string[] queries = {
             string[] queries = {
 
 
@@ -61,13 +56,11 @@ namespace MediaBrowser.Server.Implementations.Persistence
                                 "pragma shrink_memory"
                                 "pragma shrink_memory"
                                };
                                };
 
 
-            _connection.RunQueries(queries, _logger);
+            _connection.RunQueries(queries, Logger);
 
 
             AddItemDateModifiedCommand();
             AddItemDateModifiedCommand();
 
 
             PrepareStatements();
             PrepareStatements();
-
-            _shrinkMemoryTimer = new SqliteShrinkMemoryTimer(_connection, _writeLock, _logger);
         }
         }
 
 
         private static readonly string[] StatusColumns =
         private static readonly string[] StatusColumns =
@@ -113,14 +106,9 @@ namespace MediaBrowser.Server.Implementations.Persistence
             builder.AppendLine("alter table MetadataStatus");
             builder.AppendLine("alter table MetadataStatus");
             builder.AppendLine("add column ItemDateModified DateTime NULL");
             builder.AppendLine("add column ItemDateModified DateTime NULL");
 
 
-            _connection.RunQueries(new[] { builder.ToString() }, _logger);
+            _connection.RunQueries(new[] { builder.ToString() }, Logger);
         }
         }
         
         
-        /// <summary>
-        /// The _write lock
-        /// </summary>
-        private readonly SemaphoreSlim _writeLock = new SemaphoreSlim(1, 1);
-
         /// <summary>
         /// <summary>
         /// Prepares the statements.
         /// Prepares the statements.
         /// </summary>
         /// </summary>
@@ -227,7 +215,7 @@ namespace MediaBrowser.Server.Implementations.Persistence
 
 
             cancellationToken.ThrowIfCancellationRequested();
             cancellationToken.ThrowIfCancellationRequested();
 
 
-            await _writeLock.WaitAsync(cancellationToken).ConfigureAwait(false);
+            await WriteLock.WaitAsync(cancellationToken).ConfigureAwait(false);
 
 
             IDbTransaction transaction = null;
             IDbTransaction transaction = null;
 
 
@@ -264,7 +252,7 @@ namespace MediaBrowser.Server.Implementations.Persistence
             }
             }
             catch (Exception e)
             catch (Exception e)
             {
             {
-                _logger.ErrorException("Failed to save provider info:", e);
+                Logger.ErrorException("Failed to save provider info:", e);
 
 
                 if (transaction != null)
                 if (transaction != null)
                 {
                 {
@@ -280,55 +268,21 @@ namespace MediaBrowser.Server.Implementations.Persistence
                     transaction.Dispose();
                     transaction.Dispose();
                 }
                 }
 
 
-                _writeLock.Release();
+                WriteLock.Release();
             }
             }
         }
         }
 
 
-        /// <summary>
-        /// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources.
-        /// </summary>
-        public void Dispose()
-        {
-            Dispose(true);
-            GC.SuppressFinalize(this);
-        }
-
-        private readonly object _disposeLock = new object();
-
-        /// <summary>
-        /// Releases unmanaged and - optionally - managed resources.
-        /// </summary>
-        /// <param name="dispose"><c>true</c> to release both managed and unmanaged resources; <c>false</c> to release only unmanaged resources.</param>
-        protected virtual void Dispose(bool dispose)
+        protected override void CloseConnection()
         {
         {
-            if (dispose)
+            if (_connection != null)
             {
             {
-                try
+                if (_connection.IsOpen())
                 {
                 {
-                    lock (_disposeLock)
-                    {
-                        if (_shrinkMemoryTimer != null)
-                        {
-                            _shrinkMemoryTimer.Dispose();
-                            _shrinkMemoryTimer = null;
-                        }
-
-                        if (_connection != null)
-                        {
-                            if (_connection.IsOpen())
-                            {
-                                _connection.Close();
-                            }
-
-                            _connection.Dispose();
-                            _connection = null;
-                        }
-                    }
-                }
-                catch (Exception ex)
-                {
-                    _logger.ErrorException("Error disposing database", ex);
+                    _connection.Close();
                 }
                 }
+
+                _connection.Dispose();
+                _connection = null;
             }
             }
         }
         }
     }
     }

+ 0 - 84
MediaBrowser.Server.Implementations/Persistence/SqliteShrinkMemoryTimer.cs

@@ -1,84 +0,0 @@
-using MediaBrowser.Model.Logging;
-using System;
-using System.Data;
-using System.Threading;
-
-namespace MediaBrowser.Server.Implementations.Persistence
-{
-    class SqliteShrinkMemoryTimer : IDisposable
-    {
-        private Timer _shrinkMemoryTimer;
-
-        private readonly SemaphoreSlim _writeLock;
-        private readonly ILogger _logger;
-        private readonly IDbConnection _connection;
-
-        public SqliteShrinkMemoryTimer(IDbConnection connection, SemaphoreSlim writeLock, ILogger logger)
-        {
-            _connection = connection;
-            _writeLock = writeLock;
-            _logger = logger;
-
-            _shrinkMemoryTimer = new Timer(TimerCallback, null, TimeSpan.FromMinutes(30), TimeSpan.FromMinutes(10));
-        }
-
-        private async void TimerCallback(object state)
-        {
-            await _writeLock.WaitAsync(CancellationToken.None).ConfigureAwait(false);
-
-            IDbTransaction transaction = null;
-
-            try
-            {
-                transaction = _connection.BeginTransaction();
-
-                using (var cmd = _connection.CreateCommand())
-                {
-                    cmd.Transaction = transaction;
-                    cmd.CommandText = "pragma shrink_memory";
-                    cmd.ExecuteNonQuery();
-                }
-
-                transaction.Commit();
-            }
-            catch (OperationCanceledException)
-            {
-                if (transaction != null)
-                {
-                    transaction.Rollback();
-                }
-
-                throw;
-            }
-            catch (Exception e)
-            {
-                _logger.ErrorException("Failed to save items:", e);
-
-                if (transaction != null)
-                {
-                    transaction.Rollback();
-                }
-
-                throw;
-            }
-            finally
-            {
-                if (transaction != null)
-                {
-                    transaction.Dispose();
-                }
-
-                _writeLock.Release();
-            }
-        }
-
-        public void Dispose()
-        {
-            if (_shrinkMemoryTimer != null)
-            {
-                _shrinkMemoryTimer.Dispose();
-                _shrinkMemoryTimer = null;
-            }
-        }
-    }
-}

+ 22 - 82
MediaBrowser.Server.Implementations/Persistence/SqliteUserDataRepository.cs

@@ -11,13 +11,15 @@ using System.Threading.Tasks;
 
 
 namespace MediaBrowser.Server.Implementations.Persistence
 namespace MediaBrowser.Server.Implementations.Persistence
 {
 {
-    public class SqliteUserDataRepository : IUserDataRepository
+    public class SqliteUserDataRepository : BaseSqliteRepository, IUserDataRepository
     {
     {
-        private readonly ILogger _logger;
-
-        private readonly SemaphoreSlim _writeLock = new SemaphoreSlim(1, 1);
-
         private IDbConnection _connection;
         private IDbConnection _connection;
+        private readonly IApplicationPaths _appPaths;
+
+        public SqliteUserDataRepository(ILogManager logManager, IApplicationPaths appPaths) : base(logManager)
+        {
+            _appPaths = appPaths;
+        }
 
 
         /// <summary>
         /// <summary>
         /// Gets the name of the repository
         /// Gets the name of the repository
@@ -31,32 +33,6 @@ namespace MediaBrowser.Server.Implementations.Persistence
             }
             }
         }
         }
 
 
-        /// <summary>
-        /// The _app paths
-        /// </summary>
-        private readonly IApplicationPaths _appPaths;
-
-        /// <summary>
-        /// Initializes a new instance of the <see cref="SqliteUserDataRepository" /> class.
-        /// </summary>
-        /// <param name="appPaths">The app paths.</param>
-        /// <param name="logManager">The log manager.</param>
-        /// <exception cref="System.ArgumentNullException">jsonSerializer
-        /// or
-        /// appPaths</exception>
-        public SqliteUserDataRepository(IApplicationPaths appPaths, ILogManager logManager)
-        {
-            if (appPaths == null)
-            {
-                throw new ArgumentNullException("appPaths");
-            }
-
-            _appPaths = appPaths;
-            _logger = logManager.GetLogger(GetType().Name);
-        }
-
-        private SqliteShrinkMemoryTimer _shrinkMemoryTimer;
-
         /// <summary>
         /// <summary>
         /// Opens the connection to the database
         /// Opens the connection to the database
         /// </summary>
         /// </summary>
@@ -65,7 +41,7 @@ namespace MediaBrowser.Server.Implementations.Persistence
         {
         {
             var dbFile = Path.Combine(_appPaths.DataPath, "userdata_v2.db");
             var dbFile = Path.Combine(_appPaths.DataPath, "userdata_v2.db");
 
 
-            _connection = await SqliteExtensions.ConnectToDb(dbFile, _logger).ConfigureAwait(false);
+            _connection = await SqliteExtensions.ConnectToDb(dbFile, Logger).ConfigureAwait(false);
 
 
             string[] queries = {
             string[] queries = {
 
 
@@ -79,9 +55,7 @@ namespace MediaBrowser.Server.Implementations.Persistence
                                 "pragma shrink_memory"
                                 "pragma shrink_memory"
                                };
                                };
 
 
-            _connection.RunQueries(queries, _logger);
-
-            _shrinkMemoryTimer = new SqliteShrinkMemoryTimer(_connection, _writeLock, _logger);
+            _connection.RunQueries(queries, Logger);
         }
         }
 
 
         /// <summary>
         /// <summary>
@@ -143,7 +117,7 @@ namespace MediaBrowser.Server.Implementations.Persistence
         {
         {
             cancellationToken.ThrowIfCancellationRequested();
             cancellationToken.ThrowIfCancellationRequested();
 
 
-            await _writeLock.WaitAsync(cancellationToken).ConfigureAwait(false);
+            await WriteLock.WaitAsync(cancellationToken).ConfigureAwait(false);
 
 
             IDbTransaction transaction = null;
             IDbTransaction transaction = null;
 
 
@@ -182,7 +156,7 @@ namespace MediaBrowser.Server.Implementations.Persistence
             }
             }
             catch (Exception e)
             catch (Exception e)
             {
             {
-                _logger.ErrorException("Failed to save user data:", e);
+                Logger.ErrorException("Failed to save user data:", e);
 
 
                 if (transaction != null)
                 if (transaction != null)
                 {
                 {
@@ -198,7 +172,7 @@ namespace MediaBrowser.Server.Implementations.Persistence
                     transaction.Dispose();
                     transaction.Dispose();
                 }
                 }
 
 
-                _writeLock.Release();
+                WriteLock.Release();
             }
             }
         }
         }
 
 
@@ -213,7 +187,7 @@ namespace MediaBrowser.Server.Implementations.Persistence
         {
         {
             cancellationToken.ThrowIfCancellationRequested();
             cancellationToken.ThrowIfCancellationRequested();
 
 
-            await _writeLock.WaitAsync(cancellationToken).ConfigureAwait(false);
+            await WriteLock.WaitAsync(cancellationToken).ConfigureAwait(false);
 
 
             IDbTransaction transaction = null;
             IDbTransaction transaction = null;
 
 
@@ -257,7 +231,7 @@ namespace MediaBrowser.Server.Implementations.Persistence
             }
             }
             catch (Exception e)
             catch (Exception e)
             {
             {
-                _logger.ErrorException("Failed to save user data:", e);
+                Logger.ErrorException("Failed to save user data:", e);
 
 
                 if (transaction != null)
                 if (transaction != null)
                 {
                 {
@@ -273,7 +247,7 @@ namespace MediaBrowser.Server.Implementations.Persistence
                     transaction.Dispose();
                     transaction.Dispose();
                 }
                 }
 
 
-                _writeLock.Release();
+                WriteLock.Release();
             }
             }
         }
         }
 
 
@@ -379,51 +353,17 @@ namespace MediaBrowser.Server.Implementations.Persistence
             return userData;
             return userData;
         }
         }
 
 
-        /// <summary>
-        /// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources.
-        /// </summary>
-        public void Dispose()
-        {
-            Dispose(true);
-            GC.SuppressFinalize(this);
-        }
-
-        private readonly object _disposeLock = new object();
-
-        /// <summary>
-        /// Releases unmanaged and - optionally - managed resources.
-        /// </summary>
-        /// <param name="dispose"><c>true</c> to release both managed and unmanaged resources; <c>false</c> to release only unmanaged resources.</param>
-        protected virtual void Dispose(bool dispose)
+        protected override void CloseConnection()
         {
         {
-            if (dispose)
+            if (_connection != null)
             {
             {
-                try
+                if (_connection.IsOpen())
                 {
                 {
-                    lock (_disposeLock)
-                    {
-                        if (_shrinkMemoryTimer != null)
-                        {
-                            _shrinkMemoryTimer.Dispose();
-                            _shrinkMemoryTimer = null;
-                        }
-
-                        if (_connection != null)
-                        {
-                            if (_connection.IsOpen())
-                            {
-                                _connection.Close();
-                            }
-
-                            _connection.Dispose();
-                            _connection = null;
-                        }
-                    }
-                }
-                catch (Exception ex)
-                {
-                    _logger.ErrorException("Error disposing database", ex);
+                    _connection.Close();
                 }
                 }
+
+                _connection.Dispose();
+                _connection = null;
             }
             }
         }
         }
     }
     }

+ 24 - 75
MediaBrowser.Server.Implementations/Persistence/SqliteUserRepository.cs

@@ -15,14 +15,17 @@ namespace MediaBrowser.Server.Implementations.Persistence
     /// <summary>
     /// <summary>
     /// Class SQLiteUserRepository
     /// Class SQLiteUserRepository
     /// </summary>
     /// </summary>
-    public class SqliteUserRepository : IUserRepository
+    public class SqliteUserRepository : BaseSqliteRepository, IUserRepository
     {
     {
-        private readonly ILogger _logger;
-
-        private readonly SemaphoreSlim _writeLock = new SemaphoreSlim(1, 1);
-
         private IDbConnection _connection;
         private IDbConnection _connection;
         private readonly IServerApplicationPaths _appPaths;
         private readonly IServerApplicationPaths _appPaths;
+        private readonly IJsonSerializer _jsonSerializer;
+
+        public SqliteUserRepository(ILogManager logManager, IServerApplicationPaths appPaths, IJsonSerializer jsonSerializer) : base(logManager)
+        {
+            _appPaths = appPaths;
+            _jsonSerializer = jsonSerializer;
+        }
 
 
         /// <summary>
         /// <summary>
         /// Gets the name of the repository
         /// Gets the name of the repository
@@ -36,32 +39,6 @@ namespace MediaBrowser.Server.Implementations.Persistence
             }
             }
         }
         }
 
 
-        /// <summary>
-        /// Gets the json serializer.
-        /// </summary>
-        /// <value>The json serializer.</value>
-        private readonly IJsonSerializer _jsonSerializer;
-
-        /// <summary>
-        /// Initializes a new instance of the <see cref="SqliteUserRepository" /> class.
-        /// </summary>
-        /// <param name="jsonSerializer">The json serializer.</param>
-        /// <param name="logManager">The log manager.</param>
-        /// <param name="appPaths">The app paths.</param>
-        /// <exception cref="System.ArgumentNullException">appPaths</exception>
-        public SqliteUserRepository(IJsonSerializer jsonSerializer, ILogManager logManager, IServerApplicationPaths appPaths)
-        {
-            if (jsonSerializer == null)
-            {
-                throw new ArgumentNullException("jsonSerializer");
-            }
-
-            _jsonSerializer = jsonSerializer;
-            _appPaths = appPaths;
-
-            _logger = logManager.GetLogger(GetType().Name);
-        }
-
         /// <summary>
         /// <summary>
         /// Opens the connection to the database
         /// Opens the connection to the database
         /// </summary>
         /// </summary>
@@ -70,7 +47,7 @@ namespace MediaBrowser.Server.Implementations.Persistence
         {
         {
             var dbFile = Path.Combine(_appPaths.DataPath, "users.db");
             var dbFile = Path.Combine(_appPaths.DataPath, "users.db");
 
 
-            _connection = await SqliteExtensions.ConnectToDb(dbFile, _logger).ConfigureAwait(false);
+            _connection = await SqliteExtensions.ConnectToDb(dbFile, Logger).ConfigureAwait(false);
             
             
             string[] queries = {
             string[] queries = {
 
 
@@ -84,7 +61,7 @@ namespace MediaBrowser.Server.Implementations.Persistence
                                 "pragma shrink_memory"
                                 "pragma shrink_memory"
                                };
                                };
 
 
-            _connection.RunQueries(queries, _logger);
+            _connection.RunQueries(queries, Logger);
         }
         }
 
 
         /// <summary>
         /// <summary>
@@ -107,8 +84,8 @@ namespace MediaBrowser.Server.Implementations.Persistence
 
 
             cancellationToken.ThrowIfCancellationRequested();
             cancellationToken.ThrowIfCancellationRequested();
 
 
-            await _writeLock.WaitAsync(cancellationToken).ConfigureAwait(false);
-
+            await WriteLock.WaitAsync(cancellationToken).ConfigureAwait(false);
+            
             IDbTransaction transaction = null;
             IDbTransaction transaction = null;
 
 
             try
             try
@@ -139,7 +116,7 @@ namespace MediaBrowser.Server.Implementations.Persistence
             }
             }
             catch (Exception e)
             catch (Exception e)
             {
             {
-                _logger.ErrorException("Failed to save user:", e);
+                Logger.ErrorException("Failed to save user:", e);
 
 
                 if (transaction != null)
                 if (transaction != null)
                 {
                 {
@@ -155,7 +132,7 @@ namespace MediaBrowser.Server.Implementations.Persistence
                     transaction.Dispose();
                     transaction.Dispose();
                 }
                 }
 
 
-                _writeLock.Release();
+                WriteLock.Release();
             }
             }
         }
         }
 
 
@@ -199,7 +176,7 @@ namespace MediaBrowser.Server.Implementations.Persistence
 
 
             cancellationToken.ThrowIfCancellationRequested();
             cancellationToken.ThrowIfCancellationRequested();
 
 
-            await _writeLock.WaitAsync(cancellationToken).ConfigureAwait(false);
+            await WriteLock.WaitAsync(cancellationToken).ConfigureAwait(false);
 
 
             IDbTransaction transaction = null;
             IDbTransaction transaction = null;
 
 
@@ -231,7 +208,7 @@ namespace MediaBrowser.Server.Implementations.Persistence
             }
             }
             catch (Exception e)
             catch (Exception e)
             {
             {
-                _logger.ErrorException("Failed to delete user:", e);
+                Logger.ErrorException("Failed to delete user:", e);
 
 
                 if (transaction != null)
                 if (transaction != null)
                 {
                 {
@@ -247,49 +224,21 @@ namespace MediaBrowser.Server.Implementations.Persistence
                     transaction.Dispose();
                     transaction.Dispose();
                 }
                 }
 
 
-                _writeLock.Release();
+                WriteLock.Release();
             }
             }
         }
         }
 
 
-        /// <summary>
-        /// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources.
-        /// </summary>
-        public void Dispose()
-        {
-            Dispose(true);
-            GC.SuppressFinalize(this);
-        }
-
-        private readonly object _disposeLock = new object();
-
-        /// <summary>
-        /// Releases unmanaged and - optionally - managed resources.
-        /// </summary>
-        /// <param name="dispose"><c>true</c> to release both managed and unmanaged resources; <c>false</c> to release only unmanaged resources.</param>
-        protected virtual void Dispose(bool dispose)
+        protected override void CloseConnection()
         {
         {
-            if (dispose)
+            if (_connection != null)
             {
             {
-                try
-                {
-                    lock (_disposeLock)
-                    {
-                        if (_connection != null)
-                        {
-                            if (_connection.IsOpen())
-                            {
-                                _connection.Close();
-                            }
-
-                            _connection.Dispose();
-                            _connection = null;
-                        }
-                    }
-                }
-                catch (Exception ex)
+                if (_connection.IsOpen())
                 {
                 {
-                    _logger.ErrorException("Error disposing database", ex);
+                    _connection.Close();
                 }
                 }
+
+                _connection.Dispose();
+                _connection = null;
             }
             }
         }
         }
     }
     }

+ 29 - 2
MediaBrowser.Server.Implementations/Photos/BaseDynamicImageProvider.cs

@@ -191,6 +191,8 @@ namespace MediaBrowser.Server.Implementations.Photos
             throw new ArgumentException("Unexpected image type");
             throw new ArgumentException("Unexpected image type");
         }
         }
 
 
+        private const int MaxImageAgeDays = 7;
+
         public bool HasChanged(IHasMetadata item, IDirectoryService directoryService, DateTime date)
         public bool HasChanged(IHasMetadata item, IDirectoryService directoryService, DateTime date)
         {
         {
             if (!Supports(item))
             if (!Supports(item))
@@ -198,6 +200,11 @@ namespace MediaBrowser.Server.Implementations.Photos
                 return false;
                 return false;
             }
             }
 
 
+            if (item is UserView)
+            {
+                return HasChanged(item, ImageType.Primary) || HasChanged(item, ImageType.Thumb);
+            }
+
             var items = GetItemsWithImages(item).Result;
             var items = GetItemsWithImages(item).Result;
             var cacheKey = GetConfigurationCacheKey(items, item.Name);
             var cacheKey = GetConfigurationCacheKey(items, item.Name);
 
 
@@ -216,7 +223,6 @@ namespace MediaBrowser.Server.Implementations.Photos
                 }
                 }
 
 
                 var currentPathCacheKey = (Path.GetFileNameWithoutExtension(image.Path) ?? string.Empty).Split('_').LastOrDefault();
                 var currentPathCacheKey = (Path.GetFileNameWithoutExtension(image.Path) ?? string.Empty).Split('_').LastOrDefault();
-
                 if (string.Equals(cacheKey, currentPathCacheKey, StringComparison.OrdinalIgnoreCase))
                 if (string.Equals(cacheKey, currentPathCacheKey, StringComparison.OrdinalIgnoreCase))
                 {
                 {
                     return false;
                     return false;
@@ -226,6 +232,27 @@ namespace MediaBrowser.Server.Implementations.Photos
             return true;
             return true;
         }
         }
 
 
+        protected bool HasChanged(IHasImages item, ImageType type)
+        {
+            var image = item.GetImageInfo(type, 0);
+
+            if (image != null)
+            {
+                if (!FileSystem.ContainsSubPath(item.GetInternalMetadataPath(), image.Path))
+                {
+                    return false;
+                }
+
+                var age = DateTime.UtcNow - image.DateModified;
+                if (age.TotalDays <= MaxImageAgeDays)
+                {
+                    return false;
+                }
+            }
+
+            return true;
+        }
+
         protected List<BaseItem> GetFinalItems(List<BaseItem> items)
         protected List<BaseItem> GetFinalItems(List<BaseItem> items)
         {
         {
             return GetFinalItems(items, 4);
             return GetFinalItems(items, 4);
@@ -234,7 +261,7 @@ namespace MediaBrowser.Server.Implementations.Photos
         protected virtual List<BaseItem> GetFinalItems(List<BaseItem> items, int limit)
         protected virtual List<BaseItem> GetFinalItems(List<BaseItem> items, int limit)
         {
         {
             // Rotate the images once every x days
             // Rotate the images once every x days
-            var random = DateTime.Now.DayOfYear % 7;
+            var random = DateTime.Now.DayOfYear % MaxImageAgeDays;
 
 
             return items
             return items
                 .OrderBy(i => (random + "" + items.IndexOf(i)).GetMD5())
                 .OrderBy(i => (random + "" + items.IndexOf(i)).GetMD5())

+ 2 - 1
MediaBrowser.Server.Implementations/Photos/PhotoAlbumImageProvider.cs

@@ -11,7 +11,8 @@ namespace MediaBrowser.Server.Implementations.Photos
 {
 {
     //public class PhotoAlbumImageProvider : BaseDynamicImageProvider<PhotoAlbum>
     //public class PhotoAlbumImageProvider : BaseDynamicImageProvider<PhotoAlbum>
     //{
     //{
-    //    public PhotoAlbumImageProvider(IFileSystem fileSystem, IProviderManager providerManager, IApplicationPaths applicationPaths, IImageProcessor imageProcessor) : base(fileSystem, providerManager, applicationPaths, imageProcessor)
+    //    public PhotoAlbumImageProvider(IFileSystem fileSystem, IProviderManager providerManager, IApplicationPaths applicationPaths, IImageProcessor imageProcessor)
+    //        : base(fileSystem, providerManager, applicationPaths, imageProcessor)
     //    {
     //    {
     //    }
     //    }
 
 

+ 1 - 1
MediaBrowser.Server.Implementations/Session/SessionManager.cs

@@ -1550,7 +1550,7 @@ namespace MediaBrowser.Server.Implementations.Session
 
 
                 if (info.PrimaryImageTag == null)
                 if (info.PrimaryImageTag == null)
                 {
                 {
-                    var album = audio.Parents.OfType<MusicAlbum>().FirstOrDefault();
+                    var album = audio.AlbumEntity;
 
 
                     if (album != null && album.HasImage(ImageType.Primary))
                     if (album != null && album.HasImage(ImageType.Primary))
                     {
                     {

+ 2 - 4
MediaBrowser.Server.Implementations/UserViews/DynamicImageProvider.cs

@@ -21,13 +21,11 @@ namespace MediaBrowser.Server.Implementations.UserViews
     public class DynamicImageProvider : BaseDynamicImageProvider<UserView>
     public class DynamicImageProvider : BaseDynamicImageProvider<UserView>
     {
     {
         private readonly IUserManager _userManager;
         private readonly IUserManager _userManager;
-        private readonly ILibraryManager _libraryManager;
 
 
-        public DynamicImageProvider(IFileSystem fileSystem, IProviderManager providerManager, IApplicationPaths applicationPaths, IImageProcessor imageProcessor, IUserManager userManager, ILibraryManager libraryManager)
+        public DynamicImageProvider(IFileSystem fileSystem, IProviderManager providerManager, IApplicationPaths applicationPaths, IImageProcessor imageProcessor, IUserManager userManager)
             : base(fileSystem, providerManager, applicationPaths, imageProcessor)
             : base(fileSystem, providerManager, applicationPaths, imageProcessor)
         {
         {
             _userManager = userManager;
             _userManager = userManager;
-            _libraryManager = libraryManager;
         }
         }
 
 
         public override IEnumerable<ImageType> GetSupportedImages(IHasImages item)
         public override IEnumerable<ImageType> GetSupportedImages(IHasImages item)
@@ -122,7 +120,7 @@ namespace MediaBrowser.Server.Implementations.UserViews
                 var audio = i as Audio;
                 var audio = i as Audio;
                 if (audio != null)
                 if (audio != null)
                 {
                 {
-                    var album = audio.FindParent<MusicAlbum>();
+                    var album = audio.AlbumEntity;
                     if (album != null && album.HasImage(ImageType.Primary))
                     if (album != null && album.HasImage(ImageType.Primary))
                     {
                     {
                         return album;
                         return album;

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

@@ -1,9 +1,9 @@
 <?xml version="1.0" encoding="utf-8"?>
 <?xml version="1.0" encoding="utf-8"?>
 <packages>
 <packages>
   <package id="Interfaces.IO" version="1.0.0.5" targetFramework="net45" />
   <package id="Interfaces.IO" version="1.0.0.5" targetFramework="net45" />
-  <package id="MediaBrowser.Naming" version="1.0.0.34" targetFramework="net45" />
+  <package id="MediaBrowser.Naming" version="1.0.0.35" targetFramework="net45" />
   <package id="Mono.Nat" version="1.2.24.0" targetFramework="net45" />
   <package id="Mono.Nat" version="1.2.24.0" targetFramework="net45" />
   <package id="morelinq" version="1.1.0" targetFramework="net45" />
   <package id="morelinq" version="1.1.0" targetFramework="net45" />
   <package id="Patterns.Logging" version="1.0.0.2" targetFramework="net45" />
   <package id="Patterns.Logging" version="1.0.0.2" targetFramework="net45" />
-  <package id="SocketHttpListener" version="1.0.0.5" targetFramework="net45" />
+  <package id="SocketHttpListener" version="1.0.0.6" targetFramework="net45" />
 </packages>
 </packages>

+ 4 - 4
MediaBrowser.Server.Startup.Common/ApplicationHost.cs

@@ -392,13 +392,13 @@ namespace MediaBrowser.Server.Startup.Common
             UserRepository = await GetUserRepository().ConfigureAwait(false);
             UserRepository = await GetUserRepository().ConfigureAwait(false);
             RegisterSingleInstance(UserRepository);
             RegisterSingleInstance(UserRepository);
 
 
-            DisplayPreferencesRepository = new SqliteDisplayPreferencesRepository(ApplicationPaths, JsonSerializer, LogManager);
+            DisplayPreferencesRepository = new SqliteDisplayPreferencesRepository(LogManager, JsonSerializer, ApplicationPaths);
             RegisterSingleInstance(DisplayPreferencesRepository);
             RegisterSingleInstance(DisplayPreferencesRepository);
 
 
             ItemRepository = new SqliteItemRepository(ApplicationPaths, JsonSerializer, LogManager);
             ItemRepository = new SqliteItemRepository(ApplicationPaths, JsonSerializer, LogManager);
             RegisterSingleInstance(ItemRepository);
             RegisterSingleInstance(ItemRepository);
 
 
-            ProviderRepository = new SqliteProviderInfoRepository(ApplicationPaths, LogManager);
+            ProviderRepository = new SqliteProviderInfoRepository(LogManager, ApplicationPaths);
             RegisterSingleInstance(ProviderRepository);
             RegisterSingleInstance(ProviderRepository);
 
 
             FileOrganizationRepository = await GetFileOrganizationRepository().ConfigureAwait(false);
             FileOrganizationRepository = await GetFileOrganizationRepository().ConfigureAwait(false);
@@ -614,7 +614,7 @@ namespace MediaBrowser.Server.Startup.Common
         /// <returns>Task{IUserRepository}.</returns>
         /// <returns>Task{IUserRepository}.</returns>
         private async Task<IUserRepository> GetUserRepository()
         private async Task<IUserRepository> GetUserRepository()
         {
         {
-            var repo = new SqliteUserRepository(JsonSerializer, LogManager, ApplicationPaths);
+            var repo = new SqliteUserRepository(LogManager, ApplicationPaths, JsonSerializer);
 
 
             await repo.Initialize().ConfigureAwait(false);
             await repo.Initialize().ConfigureAwait(false);
 
 
@@ -704,7 +704,7 @@ namespace MediaBrowser.Server.Startup.Common
         /// <returns>Task.</returns>
         /// <returns>Task.</returns>
         private async Task ConfigureUserDataRepositories()
         private async Task ConfigureUserDataRepositories()
         {
         {
-            var repo = new SqliteUserDataRepository(ApplicationPaths, LogManager);
+            var repo = new SqliteUserDataRepository(LogManager, ApplicationPaths);
 
 
             await repo.Initialize().ConfigureAwait(false);
             await repo.Initialize().ConfigureAwait(false);
 
 

+ 15 - 12
MediaBrowser.WebDashboard/Api/DashboardService.cs

@@ -52,6 +52,7 @@ namespace MediaBrowser.WebDashboard.Api
     [Route("/dashboard/Package", "GET")]
     [Route("/dashboard/Package", "GET")]
     public class GetDashboardPackage
     public class GetDashboardPackage
     {
     {
+        public string Mode { get; set; }
     }
     }
 
 
     /// <summary>
     /// <summary>
@@ -134,7 +135,7 @@ namespace MediaBrowser.WebDashboard.Api
         {
         {
             var page = ServerEntryPoint.Instance.PluginConfigurationPages.First(p => p.Name.Equals(request.Name, StringComparison.OrdinalIgnoreCase));
             var page = ServerEntryPoint.Instance.PluginConfigurationPages.First(p => p.Name.Equals(request.Name, StringComparison.OrdinalIgnoreCase));
 
 
-            return ResultFactory.GetStaticResult(Request, page.Plugin.Version.ToString().GetMD5(), null, null, MimeTypes.GetMimeType("page.html"), () => GetPackageCreator().ModifyHtml(page.GetHtmlStream(), null, false));
+            return ResultFactory.GetStaticResult(Request, page.Plugin.Version.ToString().GetMD5(), null, null, MimeTypes.GetMimeType("page.html"), () => GetPackageCreator().ModifyHtml(page.GetHtmlStream(), null, null, false));
         }
         }
 
 
         /// <summary>
         /// <summary>
@@ -252,7 +253,7 @@ namespace MediaBrowser.WebDashboard.Api
             var minify = _serverConfigurationManager.Configuration.EnableDashboardResourceMinification;
             var minify = _serverConfigurationManager.Configuration.EnableDashboardResourceMinification;
 
 
             return GetPackageCreator()
             return GetPackageCreator()
-                .GetResource(path, localizationCulture, _appHost.ApplicationVersion.ToString(), minify);
+                .GetResource(path, null, localizationCulture, _appHost.ApplicationVersion.ToString(), minify);
         }
         }
 
 
         private PackageCreator GetPackageCreator()
         private PackageCreator GetPackageCreator()
@@ -292,38 +293,40 @@ namespace MediaBrowser.WebDashboard.Api
 
 
             var appVersion = DateTime.UtcNow.Ticks.ToString(CultureInfo.InvariantCulture);
             var appVersion = DateTime.UtcNow.Ticks.ToString(CultureInfo.InvariantCulture);
 
 
-            await DumpHtml(creator.DashboardUIPath, path, culture, appVersion);
-            await DumpJs(creator.DashboardUIPath, path, culture, appVersion);
+            var mode = request.Mode;
 
 
-            await DumpFile("scripts/all.js", Path.Combine(path, "scripts", "all.js"), culture, appVersion).ConfigureAwait(false);
-            await DumpFile("css/all.css", Path.Combine(path, "css", "all.css"), culture, appVersion).ConfigureAwait(false);
+            await DumpHtml(creator.DashboardUIPath, path, mode, culture, appVersion);
+            await DumpJs(creator.DashboardUIPath, path, mode, culture, appVersion);
+
+            await DumpFile("scripts/all.js", Path.Combine(path, "scripts", "all.js"), mode, culture, appVersion).ConfigureAwait(false);
+            await DumpFile("css/all.css", Path.Combine(path, "css", "all.css"), mode, culture, appVersion).ConfigureAwait(false);
  
  
             return "";
             return "";
         }
         }
 
 
-        private async Task DumpHtml(string source, string destination, string culture, string appVersion)
+        private async Task DumpHtml(string source, string destination, string mode, string culture, string appVersion)
         {
         {
             foreach (var file in Directory.GetFiles(source, "*.html", SearchOption.TopDirectoryOnly))
             foreach (var file in Directory.GetFiles(source, "*.html", SearchOption.TopDirectoryOnly))
             {
             {
                 var filename = Path.GetFileName(file);
                 var filename = Path.GetFileName(file);
 
 
-                await DumpFile(filename, Path.Combine(destination, filename), culture, appVersion).ConfigureAwait(false);
+                await DumpFile(filename, Path.Combine(destination, filename), mode, culture, appVersion).ConfigureAwait(false);
             }
             }
         }
         }
 
 
-        private async Task DumpJs(string source, string destination, string culture, string appVersion)
+        private async Task DumpJs(string source, string mode, string destination, string culture, string appVersion)
         {
         {
             foreach (var file in Directory.GetFiles(source, "*.js", SearchOption.TopDirectoryOnly))
             foreach (var file in Directory.GetFiles(source, "*.js", SearchOption.TopDirectoryOnly))
             {
             {
                 var filename = Path.GetFileName(file);
                 var filename = Path.GetFileName(file);
 
 
-                await DumpFile("scripts/" + filename, Path.Combine(destination, "scripts", filename), culture, appVersion).ConfigureAwait(false);
+                await DumpFile("scripts/" + filename, Path.Combine(destination, "scripts", filename), mode, culture, appVersion).ConfigureAwait(false);
             }
             }
         }
         }
 
 
-        private async Task DumpFile(string resourceVirtualPath, string destinationFilePath, string culture, string appVersion)
+        private async Task DumpFile(string resourceVirtualPath, string destinationFilePath, string mode, string culture, string appVersion)
         {
         {
-            using (var stream = await GetPackageCreator().GetResource(resourceVirtualPath, culture, appVersion, true).ConfigureAwait(false))
+            using (var stream = await GetPackageCreator().GetResource(resourceVirtualPath, mode, culture, appVersion, true).ConfigureAwait(false))
             {
             {
                 using (var fs = _fileSystem.GetFileStream(destinationFilePath, FileMode.Create, FileAccess.Write, FileShare.Read))
                 using (var fs = _fileSystem.GetFileStream(destinationFilePath, FileMode.Create, FileAccess.Write, FileShare.Read))
                 {
                 {

+ 57 - 21
MediaBrowser.WebDashboard/Api/PackageCreator.cs

@@ -32,8 +32,10 @@ namespace MediaBrowser.WebDashboard.Api
         }
         }
 
 
         public async Task<Stream> GetResource(string path,
         public async Task<Stream> GetResource(string path,
+            string mode, 
             string localizationCulture,
             string localizationCulture,
-            string appVersion, bool enableMinification)
+            string appVersion, 
+            bool enableMinification)
         {
         {
             var isHtml = IsHtml(path);
             var isHtml = IsHtml(path);
 
 
@@ -41,7 +43,7 @@ namespace MediaBrowser.WebDashboard.Api
 
 
             if (path.Equals("scripts/all.js", StringComparison.OrdinalIgnoreCase))
             if (path.Equals("scripts/all.js", StringComparison.OrdinalIgnoreCase))
             {
             {
-                resourceStream = await GetAllJavascript(localizationCulture, appVersion, enableMinification).ConfigureAwait(false);
+                resourceStream = await GetAllJavascript(mode, localizationCulture, appVersion, enableMinification).ConfigureAwait(false);
             }
             }
             else if (path.Equals("css/all.css", StringComparison.OrdinalIgnoreCase))
             else if (path.Equals("css/all.css", StringComparison.OrdinalIgnoreCase))
             {
             {
@@ -58,7 +60,7 @@ namespace MediaBrowser.WebDashboard.Api
                 // jQuery ajax doesn't seem to handle if-modified-since correctly
                 // jQuery ajax doesn't seem to handle if-modified-since correctly
                 if (isHtml)
                 if (isHtml)
                 {
                 {
-                    resourceStream = await ModifyHtml(resourceStream, localizationCulture, enableMinification).ConfigureAwait(false);
+                    resourceStream = await ModifyHtml(resourceStream, mode, localizationCulture, enableMinification).ConfigureAwait(false);
                 }
                 }
             }
             }
 
 
@@ -106,10 +108,11 @@ namespace MediaBrowser.WebDashboard.Api
         /// Modifies the HTML by adding common meta tags, css and js.
         /// Modifies the HTML by adding common meta tags, css and js.
         /// </summary>
         /// </summary>
         /// <param name="sourceStream">The source stream.</param>
         /// <param name="sourceStream">The source stream.</param>
+        /// <param name="mode">The mode.</param>
         /// <param name="localizationCulture">The localization culture.</param>
         /// <param name="localizationCulture">The localization culture.</param>
         /// <param name="enableMinification">if set to <c>true</c> [enable minification].</param>
         /// <param name="enableMinification">if set to <c>true</c> [enable minification].</param>
         /// <returns>Task{Stream}.</returns>
         /// <returns>Task{Stream}.</returns>
-        public async Task<Stream> ModifyHtml(Stream sourceStream, string localizationCulture, bool enableMinification)
+        public async Task<Stream> ModifyHtml(Stream sourceStream, string mode, string localizationCulture, bool enableMinification)
         {
         {
             using (sourceStream)
             using (sourceStream)
             {
             {
@@ -155,7 +158,7 @@ namespace MediaBrowser.WebDashboard.Api
 
 
                 var version = GetType().Assembly.GetName().Version;
                 var version = GetType().Assembly.GetName().Version;
 
 
-                html = html.Replace("<head>", "<head>" + GetMetaTags() + GetCommonCss(version) + GetCommonJavascript(version));
+                html = html.Replace("<head>", "<head>" + GetMetaTags(mode) + GetCommonCss(mode, version) + GetCommonJavascript(mode, version));
 
 
                 var bytes = Encoding.UTF8.GetBytes(html);
                 var bytes = Encoding.UTF8.GetBytes(html);
 
 
@@ -172,12 +175,19 @@ namespace MediaBrowser.WebDashboard.Api
         /// Gets the meta tags.
         /// Gets the meta tags.
         /// </summary>
         /// </summary>
         /// <returns>System.String.</returns>
         /// <returns>System.String.</returns>
-        private static string GetMetaTags()
+        private static string GetMetaTags(string mode)
         {
         {
             var sb = new StringBuilder();
             var sb = new StringBuilder();
 
 
+            if (string.Equals(mode, "cordova", StringComparison.OrdinalIgnoreCase))
+            {
+                sb.Append("<meta http-equiv=\"Content-Security-Policy\" content=\"default-src *; style-src 'self' 'unsafe-inline'; script-src 'self' 'unsafe-inline' 'unsafe-eval'\">");
+            }
+
             sb.Append("<meta http-equiv=\"X-UA-Compatibility\" content=\"IE=Edge\">");
             sb.Append("<meta http-equiv=\"X-UA-Compatibility\" content=\"IE=Edge\">");
-            sb.Append("<meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">");
+            sb.Append("<meta name=\"format-detection\" content=\"telephone=no\">");
+            sb.Append("<meta name=\"msapplication-tap-highlight\" content=\"no\">");
+            sb.Append("<meta name=\"viewport\" content=\"width=device-width, initial-scale=1, minimum-scale=1, maximum-scale=1, user-scalable=no\">");
             sb.Append("<meta name=\"apple-mobile-web-app-capable\" content=\"yes\">");
             sb.Append("<meta name=\"apple-mobile-web-app-capable\" content=\"yes\">");
             sb.Append("<meta name=\"mobile-web-app-capable\" content=\"yes\">");
             sb.Append("<meta name=\"mobile-web-app-capable\" content=\"yes\">");
             sb.Append("<meta name=\"application-name\" content=\"Emby\">");
             sb.Append("<meta name=\"application-name\" content=\"Emby\">");
@@ -200,11 +210,12 @@ namespace MediaBrowser.WebDashboard.Api
         /// <summary>
         /// <summary>
         /// Gets the common CSS.
         /// Gets the common CSS.
         /// </summary>
         /// </summary>
+        /// <param name="mode">The mode.</param>
         /// <param name="version">The version.</param>
         /// <param name="version">The version.</param>
         /// <returns>System.String.</returns>
         /// <returns>System.String.</returns>
-        private string GetCommonCss(Version version)
+        private string GetCommonCss(string mode, Version version)
         {
         {
-            var versionString = "?v=" + version;
+            var versionString = !string.Equals(mode, "cordova", StringComparison.OrdinalIgnoreCase) ? "?v=" + version : string.Empty;
 
 
             var files = new[]
             var files = new[]
                             {
                             {
@@ -223,20 +234,26 @@ namespace MediaBrowser.WebDashboard.Api
         /// <summary>
         /// <summary>
         /// Gets the common javascript.
         /// Gets the common javascript.
         /// </summary>
         /// </summary>
+        /// <param name="mode">The mode.</param>
         /// <param name="version">The version.</param>
         /// <param name="version">The version.</param>
         /// <returns>System.String.</returns>
         /// <returns>System.String.</returns>
-        private string GetCommonJavascript(Version version)
+        private string GetCommonJavascript(string mode, Version version)
         {
         {
             var builder = new StringBuilder();
             var builder = new StringBuilder();
 
 
-            var versionString = "?v=" + version;
+            var versionString = !string.Equals(mode, "cordova", StringComparison.OrdinalIgnoreCase) ? "?v=" + version : string.Empty;
 
 
-            var files = new[]
-                            {
-                                "scripts/all.js" + versionString,
-                                "thirdparty/swipebox-master/js/jquery.swipebox.min.js" + versionString
+            var files = new List<string>
+            {
+                "scripts/all.js" + versionString,
+                "thirdparty/swipebox-master/js/jquery.swipebox.min.js" + versionString
             };
             };
 
 
+            if (string.Equals(mode, "cordova", StringComparison.OrdinalIgnoreCase))
+            {
+                files.Insert(0, "cordova.js");
+            }
+
             var tags = files.Select(s => string.Format("<script src=\"{0}\"></script>", s)).ToArray();
             var tags = files.Select(s => string.Format("<script src=\"{0}\"></script>", s)).ToArray();
 
 
             builder.Append(string.Join(string.Empty, tags));
             builder.Append(string.Join(string.Empty, tags));
@@ -248,7 +265,7 @@ namespace MediaBrowser.WebDashboard.Api
         /// Gets a stream containing all concatenated javascript
         /// Gets a stream containing all concatenated javascript
         /// </summary>
         /// </summary>
         /// <returns>Task{Stream}.</returns>
         /// <returns>Task{Stream}.</returns>
-        private async Task<Stream> GetAllJavascript(string culture, string version, bool enableMinification)
+        private async Task<Stream> GetAllJavascript(string mode, string culture, string version, bool enableMinification)
         {
         {
             var memoryStream = new MemoryStream();
             var memoryStream = new MemoryStream();
             var newLineBytes = Encoding.UTF8.GetBytes(Environment.NewLine);
             var newLineBytes = Encoding.UTF8.GetBytes(Environment.NewLine);
@@ -264,9 +281,18 @@ namespace MediaBrowser.WebDashboard.Api
 
 
             await AppendResource(memoryStream, "thirdparty/jstree3.0.8/jstree.js", newLineBytes).ConfigureAwait(false);
             await AppendResource(memoryStream, "thirdparty/jstree3.0.8/jstree.js", newLineBytes).ConfigureAwait(false);
 
 
+            await AppendResource(memoryStream, "thirdparty/fastclick.js", newLineBytes).ConfigureAwait(false);
+            await AppendResource(memoryStream, "thirdparty/headroom.js", newLineBytes).ConfigureAwait(false);
+            
             await AppendLocalization(memoryStream, culture).ConfigureAwait(false);
             await AppendLocalization(memoryStream, culture).ConfigureAwait(false);
             await memoryStream.WriteAsync(newLineBytes, 0, newLineBytes.Length).ConfigureAwait(false);
             await memoryStream.WriteAsync(newLineBytes, 0, newLineBytes.Length).ConfigureAwait(false);
 
 
+            if (!string.IsNullOrWhiteSpace(mode))
+            {
+                var appModeBytes = Encoding.UTF8.GetBytes(string.Format("window.appMode='{0}';", mode));
+                await memoryStream.WriteAsync(appModeBytes, 0, appModeBytes.Length).ConfigureAwait(false);
+            }
+
             // Write the version string for the dashboard comparison function
             // Write the version string for the dashboard comparison function
             var versionString = string.Format("window.dashboardVersion='{0}';", version);
             var versionString = string.Format("window.dashboardVersion='{0}';", version);
             var versionBytes = Encoding.UTF8.GetBytes(versionString);
             var versionBytes = Encoding.UTF8.GetBytes(versionString);
@@ -276,7 +302,7 @@ namespace MediaBrowser.WebDashboard.Api
 
 
             var builder = new StringBuilder();
             var builder = new StringBuilder();
 
 
-            foreach (var file in new[]
+            var apiClientFiles = new[]
             {
             {
                 "thirdparty/apiclient/logger.js",
                 "thirdparty/apiclient/logger.js",
                 "thirdparty/apiclient/md5.js",
                 "thirdparty/apiclient/md5.js",
@@ -289,10 +315,20 @@ namespace MediaBrowser.WebDashboard.Api
                 "thirdparty/apiclient/events.js",
                 "thirdparty/apiclient/events.js",
                 "thirdparty/apiclient/deferred.js",
                 "thirdparty/apiclient/deferred.js",
                 "thirdparty/apiclient/apiclient.js",
                 "thirdparty/apiclient/apiclient.js",
-                "thirdparty/apiclient/connectservice.js",
-                "thirdparty/apiclient/serverdiscovery.js",
-                "thirdparty/apiclient/connectionmanager.js"
-            })
+                "thirdparty/apiclient/connectservice.js"
+            }.ToList();
+
+            if (string.Equals(mode, "cordova", StringComparison.OrdinalIgnoreCase))
+            {
+                apiClientFiles.Add("thirdparty/apiclient/cordova/serverdiscovery.js");
+            }
+            else
+            {
+                apiClientFiles.Add("thirdparty/apiclient/serverdiscovery.js");
+            }
+            apiClientFiles.Add("thirdparty/apiclient/connectionmanager.js");
+
+            foreach (var file in apiClientFiles)
             {
             {
                 using (var fs = _fileSystem.GetFileStream(GetDashboardResourcePath(file), FileMode.Open, FileAccess.Read, FileShare.ReadWrite, true))
                 using (var fs = _fileSystem.GetFileStream(GetDashboardResourcePath(file), FileMode.Open, FileAccess.Read, FileShare.ReadWrite, true))
                 {
                 {

+ 13 - 1
MediaBrowser.WebDashboard/MediaBrowser.WebDashboard.csproj

@@ -90,10 +90,13 @@
     <Content Include="dashboard-ui\css\images\clients\androidtv-tile.png">
     <Content Include="dashboard-ui\css\images\clients\androidtv-tile.png">
       <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
       <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
     </Content>
     </Content>
+    <Content Include="dashboard-ui\css\images\empty.png">
+      <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
+    </Content>
     <Content Include="dashboard-ui\css\images\kids\bg.jpg">
     <Content Include="dashboard-ui\css\images\kids\bg.jpg">
       <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
       <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
     </Content>
     </Content>
-    <Content Include="dashboard-ui\css\images\server.png">
+    <Content Include="dashboard-ui\css\images\logo536.png">
       <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
       <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
     </Content>
     </Content>
     <Content Include="dashboard-ui\css\images\splash.jpg">
     <Content Include="dashboard-ui\css\images\splash.jpg">
@@ -216,6 +219,9 @@
     <Content Include="dashboard-ui\thirdparty\apiclient\connectservice.js">
     <Content Include="dashboard-ui\thirdparty\apiclient\connectservice.js">
       <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
       <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
     </Content>
     </Content>
+    <Content Include="dashboard-ui\thirdparty\apiclient\cordova\serverdiscovery.js">
+      <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
+    </Content>
     <Content Include="dashboard-ui\thirdparty\apiclient\deferred.js">
     <Content Include="dashboard-ui\thirdparty\apiclient\deferred.js">
       <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
       <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
     </Content>
     </Content>
@@ -996,6 +1002,9 @@
     <Content Include="dashboard-ui\thirdparty\cast_sender.js">
     <Content Include="dashboard-ui\thirdparty\cast_sender.js">
       <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
       <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
     </Content>
     </Content>
+    <Content Include="dashboard-ui\thirdparty\fastclick.js">
+      <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
+    </Content>
     <Content Include="dashboard-ui\thirdparty\fontawesome\css\font-awesome.css">
     <Content Include="dashboard-ui\thirdparty\fontawesome\css\font-awesome.css">
       <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
       <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
     </Content>
     </Content>
@@ -1005,6 +1014,9 @@
     <Content Include="dashboard-ui\thirdparty\fontawesome\fonts\fontawesome-webfont.svg">
     <Content Include="dashboard-ui\thirdparty\fontawesome\fonts\fontawesome-webfont.svg">
       <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
       <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
     </Content>
     </Content>
+    <Content Include="dashboard-ui\thirdparty\headroom.js">
+      <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
+    </Content>
     <Content Include="dashboard-ui\thirdparty\jquery-2.1.1.min.js">
     <Content Include="dashboard-ui\thirdparty\jquery-2.1.1.min.js">
       <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
       <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
     </Content>
     </Content>

+ 1 - 1
Nuget/MediaBrowser.Common.Internal.nuspec

@@ -14,7 +14,7 @@
         <dependencies>
         <dependencies>
             <dependency id="MediaBrowser.Common" version="3.0.622" />
             <dependency id="MediaBrowser.Common" version="3.0.622" />
             <dependency id="NLog" version="3.2.1" />
             <dependency id="NLog" version="3.2.1" />
-            <dependency id="SimpleInjector" version="2.7.0" />
+            <dependency id="SimpleInjector" version="2.8.0" />
         </dependencies>
         </dependencies>
     </metadata>
     </metadata>
     <files>
     <files>

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