Browse Source

Merge pull request #2250 from MediaBrowser/beta

Beta
Luke 8 năm trước cách đây
mục cha
commit
367e17826e
67 tập tin đã thay đổi với 356 bổ sung938 xóa
  1. 3 11
      MediaBrowser.Api/ItemUpdateService.cs
  2. 13 0
      MediaBrowser.Api/LiveTv/LiveTvService.cs
  3. 20 1
      MediaBrowser.Api/Playback/BaseStreamingService.cs
  4. 0 1
      MediaBrowser.Api/Playback/Hls/DynamicHlsService.cs
  5. 7 4
      MediaBrowser.Api/Playback/MediaInfoService.cs
  6. 3 1
      MediaBrowser.Common.Implementations/Logging/NLogger.cs
  7. 0 8
      MediaBrowser.Controller/Dlna/ISsdpHandler.cs
  8. 1 1
      MediaBrowser.Controller/Entities/BaseItem.cs
  9. 1 1
      MediaBrowser.Controller/Entities/BasePluginFolder.cs
  10. 0 12
      MediaBrowser.Controller/Entities/IByReferenceItem.cs
  11. 0 20
      MediaBrowser.Controller/Entities/IHasCriticRating.cs
  12. 0 12
      MediaBrowser.Controller/Entities/IHasShortOverview.cs
  13. 0 28
      MediaBrowser.Controller/Entities/ILibraryItem.cs
  14. 0 10
      MediaBrowser.Controller/Entities/ImageSourceInfo.cs
  15. 1 1
      MediaBrowser.Controller/Entities/Movies/Movie.cs
  16. 1 1
      MediaBrowser.Controller/Entities/TV/Season.cs
  17. 1 1
      MediaBrowser.Controller/Entities/Trailer.cs
  18. 1 10
      MediaBrowser.Controller/Entities/UserViewBuilder.cs
  19. 0 1
      MediaBrowser.Controller/Entities/Video.cs
  20. 7 4
      MediaBrowser.Controller/LiveTv/LiveTvChannel.cs
  21. 0 6
      MediaBrowser.Controller/MediaBrowser.Controller.csproj
  22. 4 16
      MediaBrowser.Controller/Providers/BaseItemXmlParser.cs
  23. 0 1
      MediaBrowser.Controller/Providers/DynamicImageResponse.cs
  24. 1 21
      MediaBrowser.Controller/Providers/IProviderManager.cs
  25. 23 4
      MediaBrowser.Dlna/Didl/DidlBuilder.cs
  26. 55 25
      MediaBrowser.Dlna/Main/DlnaEntryPoint.cs
  27. 0 4
      MediaBrowser.Dlna/MediaBrowser.Dlna.csproj
  28. 0 126
      MediaBrowser.Dlna/Ssdp/Datagram.cs
  29. 0 21
      MediaBrowser.Dlna/Ssdp/DeviceDiscoveryInfo.cs
  30. 0 24
      MediaBrowser.Dlna/Ssdp/Extensions.cs
  31. 0 328
      MediaBrowser.Dlna/Ssdp/SsdpHandler.cs
  32. 0 26
      MediaBrowser.Dlna/Ssdp/SsdpMessageBuilder.cs
  33. 9 17
      MediaBrowser.LocalMetadata/Savers/XmlSaverHelpers.cs
  34. 20 1
      MediaBrowser.MediaEncoding/Encoder/EncodingJobFactory.cs
  35. 2 0
      MediaBrowser.Model/Dto/MediaSourceInfo.cs
  36. 1 0
      MediaBrowser.Model/LiveTv/LiveTvOptions.cs
  37. 1 0
      MediaBrowser.Model/LiveTv/ProgramQuery.cs
  38. 2 0
      MediaBrowser.Model/MediaInfo/LiveStreamRequest.cs
  39. 2 0
      MediaBrowser.Model/MediaInfo/PlaybackInfoRequest.cs
  40. 1 0
      MediaBrowser.Model/Net/MimeTypes.cs
  41. 8 3
      MediaBrowser.Providers/Manager/ImageSaver.cs
  42. 2 2
      MediaBrowser.Providers/Manager/ItemImageProvider.cs
  43. 8 11
      MediaBrowser.Providers/Manager/MetadataService.cs
  44. 2 7
      MediaBrowser.Providers/Manager/ProviderManager.cs
  45. 8 20
      MediaBrowser.Providers/Manager/ProviderUtils.cs
  46. 30 42
      MediaBrowser.Providers/Omdb/OmdbProvider.cs
  47. 10 0
      MediaBrowser.Server.Implementations/IO/FileRefresher.cs
  48. 6 2
      MediaBrowser.Server.Implementations/Library/LibraryManager.cs
  49. 0 1
      MediaBrowser.Server.Implementations/Library/MediaSourceManager.cs
  50. 28 32
      MediaBrowser.Server.Implementations/Library/Resolvers/Movies/MovieResolver.cs
  51. 2 18
      MediaBrowser.Server.Implementations/LiveTv/EmbyTV/EmbyTV.cs
  52. 6 1
      MediaBrowser.Server.Implementations/LiveTv/EmbyTV/EncodedRecorder.cs
  53. 5 1
      MediaBrowser.Server.Implementations/LiveTv/LiveTvDtoService.cs
  54. 2 2
      MediaBrowser.Server.Implementations/LiveTv/LiveTvManager.cs
  55. 1 1
      MediaBrowser.Server.Implementations/LiveTv/LiveTvMediaSourceProvider.cs
  56. 1 1
      MediaBrowser.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunLiveStream.cs
  57. 6 3
      MediaBrowser.Server.Implementations/LiveTv/TunerHosts/M3UTunerHost.cs
  58. 34 9
      MediaBrowser.Server.Implementations/LiveTv/TunerHosts/M3uParser.cs
  59. 5 2
      MediaBrowser.Server.Implementations/LiveTv/TunerHosts/SatIp/SatIpHost.cs
  60. 1 1
      MediaBrowser.Server.Implementations/Photos/BaseDynamicImageProvider.cs
  61. 1 3
      MediaBrowser.Server.Implementations/Sorting/CriticRatingComparer.cs
  62. 1 1
      MediaBrowser.ServerApplication/MainStartup.cs
  63. 0 6
      MediaBrowser.WebDashboard/MediaBrowser.WebDashboard.csproj
  64. 4 16
      MediaBrowser.XbmcMetadata/Parsers/BaseNfoParser.cs
  65. 2 2
      Nuget/MediaBrowser.Common.Internal.nuspec
  66. 1 1
      Nuget/MediaBrowser.Common.nuspec
  67. 2 2
      Nuget/MediaBrowser.Server.Core.nuspec

+ 3 - 11
MediaBrowser.Api/ItemUpdateService.cs

@@ -245,12 +245,8 @@ namespace MediaBrowser.Api
 
             item.OriginalTitle = string.IsNullOrWhiteSpace(request.OriginalTitle) ? null : request.OriginalTitle;
 
-            var hasCriticRating = item as IHasCriticRating;
-            if (hasCriticRating != null)
-            {
-                hasCriticRating.CriticRating = request.CriticRating;
-                hasCriticRating.CriticRatingSummary = request.CriticRatingSummary;
-            }
+            item.CriticRating = request.CriticRating;
+            item.CriticRatingSummary = request.CriticRatingSummary;
 
             item.DisplayMediaType = request.DisplayMediaType;
             item.CommunityRating = request.CommunityRating;
@@ -279,11 +275,7 @@ namespace MediaBrowser.Api
                 item.Tagline = request.Taglines.FirstOrDefault();
             }
 
-            var hasShortOverview = item as IHasShortOverview;
-            if (hasShortOverview != null)
-            {
-                hasShortOverview.ShortOverview = request.ShortOverview;
-            }
+            item.ShortOverview = request.ShortOverview;
 
             item.Keywords = request.Keywords;
 

+ 13 - 0
MediaBrowser.Api/LiveTv/LiveTvService.cs

@@ -19,6 +19,7 @@ using System.Threading.Tasks;
 using CommonIO;
 using MediaBrowser.Api.Playback.Progressive;
 using MediaBrowser.Controller.Configuration;
+using MediaBrowser.Controller.Entities.TV;
 using MediaBrowser.Server.Implementations.LiveTv.EmbyTV;
 
 namespace MediaBrowser.Api.LiveTv
@@ -390,6 +391,7 @@ namespace MediaBrowser.Api.LiveTv
         public bool? EnableUserData { get; set; }
 
         public string SeriesTimerId { get; set; }
+        public string LibrarySeriesId { get; set; }
 
         /// <summary>
         /// Fields to return within the items, in addition to basic information
@@ -990,6 +992,17 @@ namespace MediaBrowser.Api.LiveTv
             query.SeriesTimerId = request.SeriesTimerId;
             query.Genres = (request.Genres ?? String.Empty).Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries);
 
+            if (!string.IsNullOrWhiteSpace(request.LibrarySeriesId))
+            {
+                query.IsSeries = true;
+
+                var series = _libraryManager.GetItemById(request.LibrarySeriesId) as Series;
+                if (series != null)
+                {
+                    query.Name = series.Name;
+                }
+            }
+
             var result = await _liveTvManager.GetPrograms(query, GetDtoOptions(request), CancellationToken.None).ConfigureAwait(false);
 
             return ToOptimizedResult(result);

+ 20 - 1
MediaBrowser.Api/Playback/BaseStreamingService.cs

@@ -317,13 +317,32 @@ namespace MediaBrowser.Api.Playback
                 }
                 if (string.Equals(hwType, "vaapi", StringComparison.OrdinalIgnoreCase) && !string.IsNullOrWhiteSpace(encodingOptions.VaapiDevice))
                 {
-                    return GetAvailableEncoder("h264_vaapi", defaultEncoder);
+                    if (IsVaapiSupported(state))
+                    {
+                        return GetAvailableEncoder("h264_vaapi", defaultEncoder);
+                    }
                 }
             }
 
             return defaultEncoder;
         }
 
+        private bool IsVaapiSupported(StreamState state)
+        {
+            var videoStream = state.VideoStream;
+
+            if (videoStream != null)
+            {
+                // vaapi will throw an error with this input
+                // [vaapi @ 0x7faed8000960] No VAAPI support for codec mpeg4 profile -99.
+                if (string.Equals(videoStream.Codec, "mpeg4", StringComparison.OrdinalIgnoreCase) && videoStream.Level == -99)
+                {
+                    return false;
+                }
+            }
+            return true;
+        }
+
         private string GetAvailableEncoder(string preferredEncoder, string defaultEncoder)
         {
             if (MediaEncoder.SupportsEncoder(preferredEncoder))

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

@@ -887,7 +887,6 @@ namespace MediaBrowser.Api.Playback.Hls
             var mapArgs = state.IsOutputVideo ? GetMapArgs(state) : string.Empty;
             var enableSplittingOnNonKeyFrames = state.VideoRequest.EnableSplittingOnNonKeyFrames && string.Equals(state.OutputVideoCodec, "copy", StringComparison.OrdinalIgnoreCase);
             enableSplittingOnNonKeyFrames = false;
-
             // TODO: check libavformat version for 57 50.100 and use -hls_flags split_by_time
             var hlsProtocolSupportsSplittingByTime = false;
 

+ 7 - 4
MediaBrowser.Api/Playback/MediaInfoService.cs

@@ -125,7 +125,7 @@ namespace MediaBrowser.Api.Playback
 
                 SetDeviceSpecificData(item, result.MediaSource, profile, authInfo, request.MaxStreamingBitrate,
                     request.StartTimeTicks ?? 0, result.MediaSource.Id, request.AudioStreamIndex,
-                    request.SubtitleStreamIndex, request.PlaySessionId, request.UserId);
+                    request.SubtitleStreamIndex, request.MaxAudioChannels, request.PlaySessionId, request.UserId);
             }
             else
             {
@@ -167,7 +167,7 @@ namespace MediaBrowser.Api.Playback
             {
                 var mediaSourceId = request.MediaSourceId;
 
-                SetDeviceSpecificData(request.Id, info, profile, authInfo, request.MaxStreamingBitrate ?? profile.MaxStreamingBitrate, request.StartTimeTicks ?? 0, mediaSourceId, request.AudioStreamIndex, request.SubtitleStreamIndex, request.UserId);
+                SetDeviceSpecificData(request.Id, info, profile, authInfo, request.MaxStreamingBitrate ?? profile.MaxStreamingBitrate, request.StartTimeTicks ?? 0, mediaSourceId, request.AudioStreamIndex, request.SubtitleStreamIndex, request.MaxAudioChannels, request.UserId);
             }
 
             return ToOptimizedResult(info);
@@ -230,13 +230,14 @@ namespace MediaBrowser.Api.Playback
             string mediaSourceId,
             int? audioStreamIndex,
             int? subtitleStreamIndex,
+            int? maxAudioChannels,
             string userId)
         {
             var item = _libraryManager.GetItemById(itemId);
 
             foreach (var mediaSource in result.MediaSources)
             {
-                SetDeviceSpecificData(item, mediaSource, profile, auth, maxBitrate, startTimeTicks, mediaSourceId, audioStreamIndex, subtitleStreamIndex, result.PlaySessionId, userId);
+                SetDeviceSpecificData(item, mediaSource, profile, auth, maxBitrate, startTimeTicks, mediaSourceId, audioStreamIndex, subtitleStreamIndex, maxAudioChannels, result.PlaySessionId, userId);
             }
 
             SortMediaSources(result, maxBitrate);
@@ -251,6 +252,7 @@ namespace MediaBrowser.Api.Playback
             string mediaSourceId,
             int? audioStreamIndex,
             int? subtitleStreamIndex,
+            int? maxAudioChannels,
             string playSessionId,
             string userId)
         {
@@ -262,7 +264,8 @@ namespace MediaBrowser.Api.Playback
                 Context = EncodingContext.Streaming,
                 DeviceId = auth.DeviceId,
                 ItemId = item.Id.ToString("N"),
-                Profile = profile
+                Profile = profile,
+                MaxAudioChannels = maxAudioChannels
             };
 
             if (string.Equals(mediaSourceId, mediaSource.Id, StringComparison.OrdinalIgnoreCase))

+ 3 - 1
MediaBrowser.Common.Implementations/Logging/NLogger.cs

@@ -127,7 +127,9 @@ namespace MediaBrowser.Common.Implementations.Logging
             {
                 for (var i = 0; i < paramList.Length; i++)
                 {
-                    message = message.Replace("{" + i + "}", paramList[i].ToString());
+                    var obj = paramList[i];
+
+                    message = message.Replace("{" + i + "}", (obj == null ? "null" : obj.ToString()));
                 }
             }
 

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

@@ -1,8 +0,0 @@
-using System;
-
-namespace MediaBrowser.Controller.Dlna
-{
-    public interface ISsdpHandler
-    {
-    }
-}

+ 1 - 1
MediaBrowser.Controller/Entities/BaseItem.cs

@@ -33,7 +33,7 @@ namespace MediaBrowser.Controller.Entities
     /// <summary>
     /// Class BaseItem
     /// </summary>
-    public abstract class BaseItem : IHasProviderIds, ILibraryItem, IHasImages, IHasUserData, IHasMetadata, IHasLookupInfo<ItemLookupInfo>
+    public abstract class BaseItem : IHasProviderIds, IHasImages, IHasUserData, IHasMetadata, IHasLookupInfo<ItemLookupInfo>
     {
         protected BaseItem()
         {

+ 1 - 1
MediaBrowser.Controller/Entities/BasePluginFolder.cs

@@ -7,7 +7,7 @@ namespace MediaBrowser.Controller.Entities
     /// Plugins derive from and export this class to create a folder that will appear in the root along
     /// with all the other actual physical folders in the system.
     /// </summary>
-    public abstract class BasePluginFolder : Folder, ICollectionFolder, IByReferenceItem
+    public abstract class BasePluginFolder : Folder, ICollectionFolder
     {
         public virtual string CollectionType
         {

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

@@ -1,12 +0,0 @@
-
-namespace MediaBrowser.Controller.Entities
-{
-    /// <summary>
-    /// This is a marker class that tells us that a particular item type may be physically resolved
-    /// more than once within the library and we need to be sure to resolve them all to the same
-    /// instance of that item.
-    /// </summary>
-    public interface IByReferenceItem
-    {
-    }
-}

+ 0 - 20
MediaBrowser.Controller/Entities/IHasCriticRating.cs

@@ -1,20 +0,0 @@
-namespace MediaBrowser.Controller.Entities
-{
-    /// <summary>
-    /// Interface IHasCriticRating
-    /// </summary>
-    public interface IHasCriticRating
-    {
-        /// <summary>
-        /// Gets or sets the critic rating.
-        /// </summary>
-        /// <value>The critic rating.</value>
-        float? CriticRating { get; set; }
-
-        /// <summary>
-        /// Gets or sets the critic rating summary.
-        /// </summary>
-        /// <value>The critic rating summary.</value>
-        string CriticRatingSummary { get; set; }
-    }
-}

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

@@ -1,12 +0,0 @@
-
-namespace MediaBrowser.Controller.Entities
-{
-    public interface IHasShortOverview
-    {
-        /// <summary>
-        /// Gets or sets the short overview.
-        /// </summary>
-        /// <value>The short overview.</value>
-        string ShortOverview { get; set; }
-    }
-}

+ 0 - 28
MediaBrowser.Controller/Entities/ILibraryItem.cs

@@ -1,28 +0,0 @@
-using System;
-
-namespace MediaBrowser.Controller.Entities
-{
-    /// <summary>
-    /// Interface ILibraryItem
-    /// </summary>
-    public interface ILibraryItem
-    {
-        /// <summary>
-        /// Gets the name.
-        /// </summary>
-        /// <value>The name.</value>
-        string Name { get; }
-
-        /// <summary>
-        /// Gets the id.
-        /// </summary>
-        /// <value>The id.</value>
-        Guid Id { get; }
-
-        /// <summary>
-        /// Gets the path.
-        /// </summary>
-        /// <value>The path.</value>
-        string Path { get; }
-    }
-}

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

@@ -1,10 +0,0 @@
-using System;
-
-namespace MediaBrowser.Controller.Entities
-{
-    public class ImageSourceInfo
-    {
-        public Guid ImagePathMD5 { get; set; }
-        public Guid ImageUrlMD5 { get; set; }
-    }
-}

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

@@ -15,7 +15,7 @@ namespace MediaBrowser.Controller.Entities.Movies
     /// <summary>
     /// Class Movie
     /// </summary>
-    public class Movie : Video, IHasCriticRating, IHasSpecialFeatures, IHasBudget, IHasTrailers, IHasAwards, IHasMetascore, IHasLookupInfo<MovieInfo>, ISupportsBoxSetGrouping, IHasOriginalTitle
+    public class Movie : Video, IHasSpecialFeatures, IHasBudget, IHasTrailers, IHasAwards, IHasMetascore, IHasLookupInfo<MovieInfo>, ISupportsBoxSetGrouping, IHasOriginalTitle
     {
         public List<Guid> SpecialFeatureIds { get; set; }
 

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

@@ -36,7 +36,7 @@ namespace MediaBrowser.Controller.Entities.TV
         {
             get
             {
-                return true;
+                return false;
             }
         }
 

+ 1 - 1
MediaBrowser.Controller/Entities/Trailer.cs

@@ -10,7 +10,7 @@ namespace MediaBrowser.Controller.Entities
     /// <summary>
     /// Class Trailer
     /// </summary>
-    public class Trailer : Video, IHasCriticRating, IHasBudget, IHasMetascore, IHasOriginalTitle, IHasLookupInfo<TrailerInfo>
+    public class Trailer : Video, IHasBudget, IHasMetascore, IHasOriginalTitle, IHasLookupInfo<TrailerInfo>
     {
         public Trailer()
         {

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

@@ -1668,16 +1668,7 @@ namespace MediaBrowser.Controller.Entities
             {
                 var val = query.MinCriticRating.Value;
 
-                var hasCriticRating = item as IHasCriticRating;
-
-                if (hasCriticRating != null)
-                {
-                    if (!(hasCriticRating.CriticRating.HasValue && hasCriticRating.CriticRating >= val))
-                    {
-                        return false;
-                    }
-                }
-                else
+                if (!(item.CriticRating.HasValue && item.CriticRating >= val))
                 {
                     return false;
                 }

+ 0 - 1
MediaBrowser.Controller/Entities/Video.cs

@@ -24,7 +24,6 @@ namespace MediaBrowser.Controller.Entities
         IHasAspectRatio,
         ISupportsPlaceHolders,
         IHasMediaSources,
-        IHasShortOverview,
         IThemeMedia
     {
         [IgnoreDataMember]

+ 7 - 4
MediaBrowser.Controller/LiveTv/LiveTvChannel.cs

@@ -78,14 +78,17 @@ namespace MediaBrowser.Controller.LiveTv
 
         protected override string CreateSortName()
         {
-            double number = 0;
-
             if (!string.IsNullOrEmpty(Number))
             {
-                double.TryParse(Number, NumberStyles.Any, CultureInfo.InvariantCulture, out number);
+                double number = 0;
+
+                if (double.TryParse(Number, NumberStyles.Any, CultureInfo.InvariantCulture, out number))
+                {
+                    return number.ToString("00000-") + (Name ?? string.Empty);
+                }
             }
 
-            return number.ToString("00000-") + (Name ?? string.Empty);
+            return Number + "-" + (Name ?? string.Empty);
         }
 
         [IgnoreDataMember]

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

@@ -111,7 +111,6 @@
     <Compile Include="Dlna\IDlnaManager.cs" />
     <Compile Include="Dlna\IEventManager.cs" />
     <Compile Include="Dlna\IMediaReceiverRegistrar.cs" />
-    <Compile Include="Dlna\ISsdpHandler.cs" />
     <Compile Include="Dlna\IUpnpService.cs" />
     <Compile Include="Dlna\SsdpMessageEventArgs.cs" />
     <Compile Include="Drawing\IImageProcessor.cs" />
@@ -132,10 +131,8 @@
     <Compile Include="Entities\Game.cs" />
     <Compile Include="Entities\GameGenre.cs" />
     <Compile Include="Entities\GameSystem.cs" />
-    <Compile Include="Entities\IByReferenceItem.cs" />
     <Compile Include="Entities\IHasAspectRatio.cs" />
     <Compile Include="Entities\IHasBudget.cs" />
-    <Compile Include="Entities\IHasCriticRating.cs" />
     <Compile Include="Entities\IHasDisplayOrder.cs" />
     <Compile Include="Entities\IHasId.cs" />
     <Compile Include="Entities\IHasImages.cs" />
@@ -146,15 +143,12 @@
     <Compile Include="Entities\IHasProgramAttributes.cs" />
     <Compile Include="Entities\IHasScreenshots.cs" />
     <Compile Include="Entities\IHasSeries.cs" />
-    <Compile Include="Entities\IHasShortOverview.cs" />
     <Compile Include="Entities\IHasSpecialFeatures.cs" />
     <Compile Include="Entities\IHasStartDate.cs" />
     <Compile Include="Entities\IHasTrailers.cs" />
     <Compile Include="Entities\IHasUserData.cs" />
     <Compile Include="Entities\IHiddenFromDisplay.cs" />
     <Compile Include="Entities\IItemByName.cs" />
-    <Compile Include="Entities\ILibraryItem.cs" />
-    <Compile Include="Entities\ImageSourceInfo.cs" />
     <Compile Include="Entities\IMetadataContainer.cs" />
     <Compile Include="Entities\InternalItemsQuery.cs" />
     <Compile Include="Entities\InternalPeopleQuery.cs" />

+ 4 - 16
MediaBrowser.Controller/Providers/BaseItemXmlParser.cs

@@ -185,14 +185,12 @@ namespace MediaBrowser.Controller.Providers
                     {
                         var text = reader.ReadElementContentAsString();
 
-                        var hasCriticRating = item as IHasCriticRating;
-
-                        if (hasCriticRating != null && !string.IsNullOrEmpty(text))
+                        if (!string.IsNullOrEmpty(text))
                         {
                             float value;
                             if (float.TryParse(text, NumberStyles.Any, _usCulture, out value))
                             {
-                                hasCriticRating.CriticRating = value;
+                                item.CriticRating = value;
                             }
                         }
 
@@ -292,12 +290,7 @@ namespace MediaBrowser.Controller.Providers
 
                         if (!string.IsNullOrWhiteSpace(val))
                         {
-                            var hasShortOverview = item as IHasShortOverview;
-
-                            if (hasShortOverview != null)
-                            {
-                                hasShortOverview.ShortOverview = val;
-                            }
+                            item.ShortOverview = val;
                         }
 
                         break;
@@ -309,12 +302,7 @@ namespace MediaBrowser.Controller.Providers
 
                         if (!string.IsNullOrWhiteSpace(val))
                         {
-                            var hasCriticRating = item as IHasCriticRating;
-
-                            if (hasCriticRating != null)
-                            {
-                                hasCriticRating.CriticRatingSummary = val;
-                            }
+                            item.CriticRatingSummary = val;
                         }
 
                         break;

+ 0 - 1
MediaBrowser.Controller/Providers/DynamicImageResponse.cs

@@ -12,7 +12,6 @@ namespace MediaBrowser.Controller.Providers
         public Stream Stream { get; set; }
         public ImageFormat Format { get; set; }
         public bool HasImage { get; set; }
-        public string InternalCacheKey { get; set; }
 
         public void SetFormatFromMimeType(string mimeType)
         {

+ 1 - 21
MediaBrowser.Controller/Providers/IProviderManager.cs

@@ -69,28 +69,8 @@ namespace MediaBrowser.Controller.Providers
         /// <summary>
         /// Saves the image.
         /// </summary>
-        /// <param name="item">The item.</param>
-        /// <param name="source">The source.</param>
-        /// <param name="mimeType">Type of the MIME.</param>
-        /// <param name="type">The type.</param>
-        /// <param name="imageIndex">Index of the image.</param>
-        /// <param name="internalCacheKey">The internal cache key.</param>
-        /// <param name="cancellationToken">The cancellation token.</param>
-        /// <returns>Task.</returns>
-        Task SaveImage(IHasImages item, Stream source, string mimeType, ImageType type, int? imageIndex, string internalCacheKey, CancellationToken cancellationToken);
-
-        /// <summary>
-        /// Saves the image.
-        /// </summary>
-        /// <param name="item">The item.</param>
-        /// <param name="source">The source.</param>
-        /// <param name="mimeType">Type of the MIME.</param>
-        /// <param name="type">The type.</param>
-        /// <param name="imageIndex">Index of the image.</param>
-        /// <param name="internalCacheKey">The internal cache key.</param>
-        /// <param name="cancellationToken">The cancellation token.</param>
         /// <returns>Task.</returns>
-        Task SaveImage(IHasImages item, string source, string mimeType, ImageType type, int? imageIndex, string internalCacheKey, CancellationToken cancellationToken);
+        Task SaveImage(IHasImages item, string source, string mimeType, ImageType type, int? imageIndex, bool? saveLocallyWithMedia, CancellationToken cancellationToken);
         
         /// <summary>
         /// Adds the metadata providers.

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

@@ -585,10 +585,9 @@ namespace MediaBrowser.Dlna.Didl
             {
                 var desc = item.Overview;
 
-                var hasShortOverview = item as IHasShortOverview;
-                if (hasShortOverview != null && !string.IsNullOrEmpty(hasShortOverview.ShortOverview))
+                if (!string.IsNullOrEmpty(item.ShortOverview))
                 {
-                    desc = hasShortOverview.ShortOverview;
+                    desc = item.ShortOverview;
                 }
 
                 if (!string.IsNullOrWhiteSpace(desc))
@@ -697,16 +696,36 @@ namespace MediaBrowser.Dlna.Didl
 
         private void AddPeople(BaseItem item, XmlElement element)
         {
-            var types = new[] { PersonType.Director, PersonType.Writer, PersonType.Producer, PersonType.Composer, "Creator" };
+            var types = new[]
+            {
+                PersonType.Director,
+                PersonType.Writer,
+                PersonType.Producer,
+                PersonType.Composer,
+                "Creator"
+            };
 
             var people = _libraryManager.GetPeople(item);
 
+            var index = 0;
+
+            // Seeing some LG models locking up due content with large lists of people
+            // The actual issue might just be due to processing a more metadata than it can handle
+            var limit = 10;
+
             foreach (var actor in people)
             {
                 var type = types.FirstOrDefault(i => string.Equals(i, actor.Type, StringComparison.OrdinalIgnoreCase) || string.Equals(i, actor.Role, StringComparison.OrdinalIgnoreCase))
                     ?? PersonType.Actor;
 
                 AddValue(element, "upnp", type.ToLower(), actor.Name, NS_UPNP);
+
+                index++;
+
+                if (index >= limit)
+                {
+                    break;
+                }
             }
         }
 

+ 55 - 25
MediaBrowser.Dlna/Main/DlnaEntryPoint.cs

@@ -19,6 +19,7 @@ using System.Net;
 using System.Threading.Tasks;
 using MediaBrowser.Controller.MediaEncoding;
 using Rssdp;
+using Rssdp.Infrastructure;
 
 namespace MediaBrowser.Dlna.Main
 {
@@ -154,8 +155,14 @@ namespace MediaBrowser.Dlna.Main
             }
         }
 
+        private void LogMessage(string msg)
+        {
+            //_logger.Debug(msg);
+        }
+
         private void StartPublishing()
         {
+            SsdpDevicePublisherBase.LogFunction = LogMessage;
             _Publisher = new SsdpDevicePublisher();
         }
 
@@ -235,48 +242,71 @@ namespace MediaBrowser.Dlna.Main
 
                 var addressString = address.ToString();
 
-                var udn = (addressString).GetMD5().ToString("N");
+                var udn = CreateUuid(addressString);
+
+                var fullService = "urn:schemas-upnp-org:device:MediaServer:1";
+
+                _logger.Info("Registering publisher for {0} on {1}", fullService, addressString);
+
+                var descriptorUri = "/dlna/" + udn + "/description.xml";
+                var uri = new Uri(_appHost.GetLocalApiUrl(address) + descriptorUri);
 
-                var services = new List<string>
+                var device = new SsdpRootDevice
+                {
+                    CacheLifetime = TimeSpan.FromSeconds(cacheLength), //How long SSDP clients can cache this info.
+                    Location = uri, // Must point to the URL that serves your devices UPnP description document. 
+                    FriendlyName = "Emby Server",
+                    Manufacturer = "Emby",
+                    ModelName = "Emby Server",
+                    Uuid = udn
+                    // This must be a globally unique value that survives reboots etc. Get from storage or embedded hardware etc.                
+                };
+
+                SetProperies(device, fullService);
+                _Publisher.AddDevice(device);
+
+                var embeddedDevices = new List<string>
                 {
-                    "urn:schemas-upnp-org:device:MediaServer:1",
                     "urn:schemas-upnp-org:service:ContentDirectory:1",
                     "urn:schemas-upnp-org:service:ConnectionManager:1",
                     "urn:microsoft.com:service:X_MS_MediaReceiverRegistrar:1"
                 };
 
-                foreach (var fullService in services)
+                foreach (var subDevice in embeddedDevices)
                 {
-                    _logger.Info("Registering publisher for {0} on {1}", fullService, addressString);
-
-                    var descriptorURI = "/dlna/" + udn + "/description.xml";
-                    var uri = new Uri(_appHost.GetLocalApiUrl(address) + descriptorURI);
-
-                    var service = fullService.Replace("urn:", string.Empty).Replace(":1", string.Empty);
-
-                    var serviceParts = service.Split(':');
-
-                    var deviceTypeNamespace = serviceParts[0].Replace('.', '-');
-
-                    var device = new SsdpRootDevice
+                    var embeddedDevice = new SsdpEmbeddedDevice
                     {
-                        CacheLifetime = TimeSpan.FromSeconds(cacheLength), //How long SSDP clients can cache this info.
-                        Location = uri, // Must point to the URL that serves your devices UPnP description document. 
-                        DeviceTypeNamespace = deviceTypeNamespace,
-                        DeviceClass = serviceParts[1],
-                        DeviceType = serviceParts[2],
-                        FriendlyName = "Emby Server",
-                        Manufacturer = "Emby",
-                        ModelName = "Emby Server",
+                        FriendlyName = device.FriendlyName,
+                        Manufacturer = device.Manufacturer,
+                        ModelName = device.ModelName,
                         Uuid = udn
                         // This must be a globally unique value that survives reboots etc. Get from storage or embedded hardware etc.                
                     };
 
-                    _Publisher.AddDevice(device);
+                    SetProperies(embeddedDevice, subDevice);
+                    device.AddDevice(embeddedDevice);
                 }
             }
         }
 
+        private string CreateUuid(string text)
+        {
+            return text.GetMD5().ToString("N");
+        }
+
+        private void SetProperies(SsdpDevice device, string fullDeviceType)
+        {
+            var service = fullDeviceType.Replace("urn:", string.Empty).Replace(":1", string.Empty);
+
+            var serviceParts = service.Split(':');
+
+            var deviceTypeNamespace = serviceParts[0].Replace('.', '-');
+
+            device.DeviceTypeNamespace = deviceTypeNamespace;
+            device.DeviceClass = serviceParts[1];
+            device.DeviceType = serviceParts[2];
+        }
+
         private readonly object _syncLock = new object();
         private void StartPlayToManager()
         {

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

@@ -108,7 +108,6 @@
     <Compile Include="Profiles\SonyBravia2014Profile.cs" />
     <Compile Include="Profiles\SonyPs4Profile.cs" />
     <Compile Include="Profiles\VlcProfile.cs" />
-    <Compile Include="Ssdp\DeviceDiscoveryInfo.cs" />
     <Compile Include="Ssdp\Extensions.cs" />
     <Compile Include="PlayTo\PlaybackProgressEventArgs.cs" />
     <Compile Include="PlayTo\PlaybackStoppedEventArgs.cs" />
@@ -130,7 +129,6 @@
     <Compile Include="Service\BaseService.cs" />
     <Compile Include="Service\ControlErrorHandler.cs" />
     <Compile Include="Service\ServiceXmlBuilder.cs" />
-    <Compile Include="Ssdp\Datagram.cs" />
     <Compile Include="Server\DescriptionXmlBuilder.cs" />
     <Compile Include="Ssdp\DeviceDiscovery.cs" />
     <Compile Include="PlayTo\SsdpHttpClient.cs" />
@@ -160,8 +158,6 @@
     <Compile Include="Properties\AssemblyInfo.cs" />
     <Compile Include="Server\Headers.cs" />
     <Compile Include="Server\UpnpDevice.cs" />
-    <Compile Include="Ssdp\SsdpMessageBuilder.cs" />
-    <Compile Include="Ssdp\SsdpHandler.cs" />
   </ItemGroup>
   <ItemGroup>
     <ProjectReference Include="..\MediaBrowser.Common\MediaBrowser.Common.csproj">

+ 0 - 126
MediaBrowser.Dlna/Ssdp/Datagram.cs

@@ -1,126 +0,0 @@
-using MediaBrowser.Model.Logging;
-using System;
-using System.Net;
-using System.Net.Sockets;
-using System.Text;
-
-namespace MediaBrowser.Dlna.Ssdp
-{
-    public class Datagram
-    {
-        public EndPoint ToEndPoint { get; private set; }
-        public EndPoint FromEndPoint { get; private set; }
-        public string Message { get; private set; }
-        public bool IsBroadcast { get; private set; }
-        public bool EnableDebugLogging { get; private set; }
-
-        private readonly ILogger _logger;
-
-        public Datagram(EndPoint toEndPoint, EndPoint fromEndPoint, ILogger logger, string message, bool isBroadcast, bool enableDebugLogging)
-        {
-            Message = message;
-            _logger = logger;
-            EnableDebugLogging = enableDebugLogging;
-            IsBroadcast = isBroadcast;
-            FromEndPoint = fromEndPoint;
-            ToEndPoint = toEndPoint;
-        }
-
-        public void Send()
-        {
-            var msg = Encoding.ASCII.GetBytes(Message);
-
-            var socket = CreateSocket();
-
-            if (socket == null)
-            {
-                return;
-            }
-
-            if (FromEndPoint != null)
-            {
-                try
-                {
-                    socket.Bind(FromEndPoint);
-                }
-                catch (Exception ex)
-                {
-                    if (EnableDebugLogging)
-                    {
-                        _logger.ErrorException("Error binding datagram socket", ex);
-                    }
-
-                    if (IsBroadcast)
-                    {
-                        CloseSocket(socket, false);
-                        return;
-                    }
-                }
-            }
-
-            try
-            {
-                socket.BeginSendTo(msg, 0, msg.Length, SocketFlags.None, ToEndPoint, result =>
-                {
-                    try
-                    {
-                        socket.EndSend(result);
-                    }
-                    catch (Exception ex)
-                    {
-                        if (EnableDebugLogging)
-                        {
-                            _logger.ErrorException("Error sending Datagram to {0} from {1}: " + Message, ex, ToEndPoint, FromEndPoint == null ? "" : FromEndPoint.ToString());
-                        }
-                    }
-                    finally
-                    {
-                        CloseSocket(socket, true);
-                    }
-                }, null);
-            }
-            catch (Exception ex)
-            {
-                _logger.ErrorException("Error sending Datagram to {0} from {1}: " + Message, ex, ToEndPoint, FromEndPoint == null ? "" : FromEndPoint.ToString());
-                CloseSocket(socket, false);
-            }
-        }
-
-        private void CloseSocket(Socket socket, bool logError)
-        {
-            try
-            {
-                socket.Close();
-            }
-            catch (Exception ex)
-            {
-                if (logError && EnableDebugLogging)
-                {
-                    _logger.ErrorException("Error closing datagram socket", ex);
-                }
-            }
-        }
-
-        private Socket CreateSocket()
-        {
-            try
-            {
-                var socket = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp);
-                socket.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, true);
-                socket.SetSocketOption(SocketOptionLevel.IP, SocketOptionName.MulticastTimeToLive, 4);
-
-                if (IsBroadcast)
-                {
-                    socket.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.Broadcast, true);
-                }
-
-                return socket;
-            }
-            catch (Exception ex)
-            {
-                _logger.ErrorException("Error creating socket", ex);
-                return null;
-            }
-        }
-    }
-}

+ 0 - 21
MediaBrowser.Dlna/Ssdp/DeviceDiscoveryInfo.cs

@@ -1,21 +0,0 @@
-using MediaBrowser.Dlna.PlayTo;
-using System;
-using System.Net;
-
-namespace MediaBrowser.Dlna.Ssdp
-{
-    public class DeviceDiscoveryInfo
-    {
-        public Device Device { get; set; }
-
-        /// <summary>
-        /// The server's ip address that the device responded to
-        /// </summary>
-        public IPAddress LocalIpAddress { get; set; }
-
-        public Uri Uri { get; set; }
-
-        public string Usn { get; set; }
-        public string Nt { get; set; }
-    }
-}

+ 0 - 24
MediaBrowser.Dlna/Ssdp/Extensions.cs

@@ -9,30 +9,6 @@ namespace MediaBrowser.Dlna.Ssdp
 {
     public static class Extensions
     {
-        public static Task<int> ReceiveAsync(this Socket socket, byte[] buffer, int offset, int size)
-        {
-            var tcs = new TaskCompletionSource<int>(socket);
-            var remoteip = new IPEndPoint(IPAddress.Any, 0);
-            var endpoint = (EndPoint)remoteip;
-
-            socket.BeginReceiveFrom(buffer, offset, size, SocketFlags.None, ref endpoint, iar =>
-            {
-                var result = (TaskCompletionSource<int>)iar.AsyncState;
-                var iarSocket = (Socket)result.Task.AsyncState;
-
-                try
-                {
-                    result.TrySetResult(iarSocket.EndReceive(iar));
-                }
-                catch (Exception exc)
-                {
-                    result.TrySetException(exc);
-                }
-            }, tcs);
-
-            return tcs.Task;
-        }
-        
         public static string GetValue(this XElement container, XName name)
         {
             var node = container.Element(name);

+ 0 - 328
MediaBrowser.Dlna/Ssdp/SsdpHandler.cs

@@ -1,328 +0,0 @@
-using MediaBrowser.Common;
-using MediaBrowser.Common.Configuration;
-using MediaBrowser.Common.Events;
-using MediaBrowser.Controller.Configuration;
-using MediaBrowser.Controller.Dlna;
-using MediaBrowser.Dlna.Server;
-using MediaBrowser.Model.Logging;
-using System;
-using System.Collections.Generic;
-using System.Globalization;
-using System.Linq;
-using System.Net;
-using System.Net.Sockets;
-using System.Text;
-using System.Threading;
-using System.Threading.Tasks;
-using Microsoft.Win32;
-
-namespace MediaBrowser.Dlna.Ssdp
-{
-    public class SsdpHandler : IDisposable, ISsdpHandler
-    {
-        private Socket _multicastSocket;
-
-        private readonly ILogger _logger;
-        private readonly IServerConfigurationManager _config;
-
-        const string SSDPAddr = "239.255.255.250";
-        const int SSDPPort = 1900;
-        private readonly string _serverSignature;
-
-        private readonly IPAddress _ssdpIp = IPAddress.Parse(SSDPAddr);
-        private readonly IPEndPoint _ssdpEndp = new IPEndPoint(IPAddress.Parse(SSDPAddr), SSDPPort);
-
-        private Timer _notificationTimer;
-
-        private bool _isDisposed;
-        private readonly Dictionary<string, List<UpnpDevice>> _devices = new Dictionary<string, List<UpnpDevice>>();
-
-        private readonly IApplicationHost _appHost;
-
-        private readonly int _unicastPort = 1901;
-        private UdpClient _unicastClient;
-
-        public SsdpHandler(ILogger logger, IServerConfigurationManager config, IApplicationHost appHost)
-        {
-            _logger = logger;
-            _config = config;
-            _appHost = appHost;
-
-            _config.NamedConfigurationUpdated += _config_ConfigurationUpdated;
-            _serverSignature = GenerateServerSignature();
-        }
-
-        private string GenerateServerSignature()
-        {
-            var os = Environment.OSVersion;
-            var pstring = os.Platform.ToString();
-            switch (os.Platform)
-            {
-                case PlatformID.Win32NT:
-                case PlatformID.Win32S:
-                case PlatformID.Win32Windows:
-                    pstring = "WIN";
-                    break;
-            }
-
-            return String.Format(
-              "{0}{1}/{2}.{3} UPnP/1.0 DLNADOC/1.5 Emby/{4}",
-              pstring,
-              IntPtr.Size * 8,
-              os.Version.Major,
-              os.Version.Minor,
-              _appHost.ApplicationVersion
-              );
-        }
-
-        void _config_ConfigurationUpdated(object sender, ConfigurationUpdateEventArgs e)
-        {
-            if (string.Equals(e.Key, "dlna", StringComparison.OrdinalIgnoreCase))
-            {
-                ReloadAliveNotifier();
-            }
-        }
-
-        public IEnumerable<UpnpDevice> RegisteredDevices
-        {
-            get
-            {
-                lock (_devices)
-                {
-                    var devices = _devices.ToList();
-
-                    return devices.SelectMany(i => i.Value).ToList();
-                }
-            }
-        }
-
-        public void Start()
-        {
-            DisposeSocket();
-            StopAliveNotifier();
-
-            RestartSocketListener();
-            ReloadAliveNotifier();
-
-            SystemEvents.PowerModeChanged -= SystemEvents_PowerModeChanged;
-            SystemEvents.PowerModeChanged += SystemEvents_PowerModeChanged;
-        }
-
-        void SystemEvents_PowerModeChanged(object sender, PowerModeChangedEventArgs e)
-        {
-            if (e.Mode == PowerModes.Resume)
-            {
-                Start();
-            }
-        }
-
-        public async void SendDatagram(string msg,
-            EndPoint endpoint,
-            EndPoint localAddress,
-            bool isBroadcast,
-            int sendCount = 3)
-        {
-            var enableDebugLogging = _config.GetDlnaConfiguration().EnableDebugLog;
-
-            for (var i = 0; i < sendCount; i++)
-            {
-                if (i > 0)
-                {
-                    await Task.Delay(500).ConfigureAwait(false);
-                }
-
-                var dgram = new Datagram(endpoint, localAddress, _logger, msg, isBroadcast, enableDebugLogging);
-                dgram.Send();
-            }
-        }
-
-        private void RestartSocketListener()
-        {
-            if (_isDisposed)
-            {
-                return;
-            }
-
-            try
-            {
-                _multicastSocket = CreateMulticastSocket();
-
-                _logger.Info("MultiCast socket created");
-            }
-            catch (Exception ex)
-            {
-                _logger.ErrorException("Error creating MultiCast socket", ex);
-                //StartSocketRetryTimer();
-            }
-        }
-
-        public void Dispose()
-        {
-            _config.NamedConfigurationUpdated -= _config_ConfigurationUpdated;
-            SystemEvents.PowerModeChanged -= SystemEvents_PowerModeChanged;
-
-            _isDisposed = true;
-
-            DisposeSocket();
-            StopAliveNotifier();
-        }
-
-        private void DisposeSocket()
-        {
-            if (_multicastSocket != null)
-            {
-                _multicastSocket.Close();
-                _multicastSocket.Dispose();
-                _multicastSocket = null;
-            }
-        }
-
-        private Socket CreateMulticastSocket()
-        {
-            var socket = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp);
-            socket.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.Broadcast, true);
-            socket.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, true);
-            socket.SetSocketOption(SocketOptionLevel.IP, SocketOptionName.MulticastTimeToLive, 4);
-            socket.SetSocketOption(SocketOptionLevel.IP, SocketOptionName.AddMembership, new MulticastOption(_ssdpIp, 0));
-
-            socket.Bind(new IPEndPoint(IPAddress.Any, SSDPPort));
-
-            return socket;
-        }
-
-        private void NotifyAll()
-        {
-            var enableDebugLogging = _config.GetDlnaConfiguration().EnableDebugLog;
-
-            if (enableDebugLogging)
-            {
-                _logger.Debug("Sending alive notifications");
-            }
-            foreach (var d in RegisteredDevices)
-            {
-                NotifyDevice(d, "alive", enableDebugLogging);
-            }
-        }
-
-        private void NotifyDevice(UpnpDevice dev, string type, bool logMessage)
-        {
-            const string header = "NOTIFY * HTTP/1.1";
-
-            var values = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);
-
-            // If needed later for non-server devices, these headers will need to be dynamic 
-            values["HOST"] = "239.255.255.250:1900";
-            values["CACHE-CONTROL"] = "max-age = 600";
-            values["LOCATION"] = dev.Descriptor.ToString();
-            values["SERVER"] = _serverSignature;
-            values["NTS"] = "ssdp:" + type;
-            values["NT"] = dev.Type;
-            values["USN"] = dev.USN;
-
-            if (logMessage)
-            {
-                _logger.Debug("{0} said {1}", dev.USN, type);
-            }
-
-            var msg = new SsdpMessageBuilder().BuildMessage(header, values);
-
-            SendDatagram(msg, _ssdpEndp, new IPEndPoint(dev.Address, 0), true, 2);
-            //SendUnicastRequest(msg, 1);
-        }
-
-        public void RegisterNotification(string uuid, Uri descriptionUri, IPAddress address, IEnumerable<string> services)
-        {
-            lock (_devices)
-            {
-                List<UpnpDevice> list;
-                List<UpnpDevice> dl;
-                if (_devices.TryGetValue(uuid, out dl))
-                {
-                    list = dl;
-                }
-                else
-                {
-                    list = new List<UpnpDevice>();
-                    _devices[uuid] = list;
-                }
-
-                list.AddRange(services.Select(i => new UpnpDevice(uuid, i, descriptionUri, address)));
-
-                NotifyAll();
-                _logger.Debug("Registered mount {0} at {1}", uuid, descriptionUri);
-            }
-        }
-
-        public void UnregisterNotification(string uuid)
-        {
-            lock (_devices)
-            {
-                List<UpnpDevice> dl;
-                if (_devices.TryGetValue(uuid, out dl))
-                {
-                    _devices.Remove(uuid);
-                    foreach (var d in dl.ToList())
-                    {
-                        NotifyDevice(d, "byebye", true);
-                    }
-
-                    _logger.Debug("Unregistered mount {0}", uuid);
-                }
-            }
-        }
-
-        private readonly object _notificationTimerSyncLock = new object();
-        private int _aliveNotifierIntervalMs;
-        private void ReloadAliveNotifier()
-        {
-            var config = _config.GetDlnaConfiguration();
-
-            if (!config.BlastAliveMessages)
-            {
-                StopAliveNotifier();
-                return;
-            }
-
-            var intervalMs = config.BlastAliveMessageIntervalSeconds * 1000;
-
-            if (_notificationTimer == null || _aliveNotifierIntervalMs != intervalMs)
-            {
-                lock (_notificationTimerSyncLock)
-                {
-                    if (_notificationTimer == null)
-                    {
-                        _logger.Debug("Starting alive notifier");
-                        const int initialDelayMs = 3000;
-                        _notificationTimer = new Timer(state => NotifyAll(), null, initialDelayMs, intervalMs);
-                    }
-                    else
-                    {
-                        _logger.Debug("Updating alive notifier");
-                        _notificationTimer.Change(intervalMs, intervalMs);
-                    }
-
-                    _aliveNotifierIntervalMs = intervalMs;
-                }
-            }
-        }
-
-        private void StopAliveNotifier()
-        {
-            lock (_notificationTimerSyncLock)
-            {
-                if (_notificationTimer != null)
-                {
-                    _logger.Debug("Stopping alive notifier");
-                    _notificationTimer.Dispose();
-                    _notificationTimer = null;
-                }
-            }
-        }
-
-        public class UdpState
-        {
-            public UdpClient UdpClient;
-            public IPEndPoint EndPoint;
-        }
-    }
-}

+ 0 - 26
MediaBrowser.Dlna/Ssdp/SsdpMessageBuilder.cs

@@ -1,26 +0,0 @@
-using System.Collections.Generic;
-using System.Text;
-
-namespace MediaBrowser.Dlna.Ssdp
-{
-    public class SsdpMessageBuilder
-    {
-        public string BuildMessage(string header, Dictionary<string, string> values)
-        {
-            var builder = new StringBuilder();
-
-            const string argFormat = "{0}: {1}\r\n";
-
-            builder.AppendFormat("{0}\r\n", header);
-
-            foreach (var pair in values)
-            {
-                builder.AppendFormat(argFormat, pair.Key, pair.Value);
-            }
-
-            builder.Append("\r\n");
-
-            return builder.ToString();
-        }
-    }
-}

+ 9 - 17
MediaBrowser.LocalMetadata/Savers/XmlSaverHelpers.cs

@@ -258,18 +258,14 @@ namespace MediaBrowser.LocalMetadata.Savers
                 builder.Append("<Type>" + SecurityElement.Escape(item.DisplayMediaType) + "</Type>");
             }
 
-            var hasCriticRating = item as IHasCriticRating;
-            if (hasCriticRating != null)
+            if (item.CriticRating.HasValue)
             {
-                if (hasCriticRating.CriticRating.HasValue)
-                {
-                    builder.Append("<CriticRating>" + SecurityElement.Escape(hasCriticRating.CriticRating.Value.ToString(UsCulture)) + "</CriticRating>");
-                }
+                builder.Append("<CriticRating>" + SecurityElement.Escape(item.CriticRating.Value.ToString(UsCulture)) + "</CriticRating>");
+            }
 
-                if (!string.IsNullOrEmpty(hasCriticRating.CriticRatingSummary))
-                {
-                    builder.Append("<CriticRatingSummary><![CDATA[" + hasCriticRating.CriticRatingSummary + "]]></CriticRatingSummary>");
-                }
+            if (!string.IsNullOrEmpty(item.CriticRatingSummary))
+            {
+                builder.Append("<CriticRatingSummary><![CDATA[" + item.CriticRatingSummary + "]]></CriticRatingSummary>");
             }
 
             if (!string.IsNullOrEmpty(item.Overview))
@@ -285,14 +281,10 @@ namespace MediaBrowser.LocalMetadata.Savers
                     builder.Append("<OriginalTitle>" + SecurityElement.Escape(hasOriginalTitle.OriginalTitle) + "</OriginalTitle>");
                 }
             }
-            
-            var hasShortOverview = item as IHasShortOverview;
-            if (hasShortOverview != null)
+
+            if (!string.IsNullOrEmpty(item.ShortOverview))
             {
-                if (!string.IsNullOrEmpty(hasShortOverview.ShortOverview))
-                {
-                    builder.Append("<ShortOverview><![CDATA[" + hasShortOverview.ShortOverview + "]]></ShortOverview>");
-                }
+                builder.Append("<ShortOverview><![CDATA[" + item.ShortOverview + "]]></ShortOverview>");
             }
 
             if (!string.IsNullOrEmpty(item.CustomRating))

+ 20 - 1
MediaBrowser.MediaEncoding/Encoder/EncodingJobFactory.cs

@@ -588,13 +588,32 @@ namespace MediaBrowser.MediaEncoding.Encoder
                 }
                 if (string.Equals(hwType, "vaapi", StringComparison.OrdinalIgnoreCase) && !string.IsNullOrWhiteSpace(options.VaapiDevice))
                 {
-                    return GetAvailableEncoder(mediaEncoder, "h264_vaapi", defaultEncoder);
+                    if (IsVaapiSupported(state))
+                    {
+                        return GetAvailableEncoder(mediaEncoder, "h264_vaapi", defaultEncoder);
+                    }
                 }
             }
 
             return defaultEncoder;
         }
 
+        private static bool IsVaapiSupported(EncodingJob state)
+        {
+            var videoStream = state.VideoStream;
+
+            if (videoStream != null)
+            {
+                // vaapi will throw an error with this input
+                // [vaapi @ 0x7faed8000960] No VAAPI support for codec mpeg4 profile -99.
+                if (string.Equals(videoStream.Codec, "mpeg4", StringComparison.OrdinalIgnoreCase) && videoStream.Level == -99)
+                {
+                    return false;
+                }
+            }
+            return true;
+        }
+
         internal static bool CanStreamCopyVideo(EncodingJobOptions request, MediaStream videoStream)
         {
             if (videoStream.IsInterlaced)

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

@@ -31,6 +31,7 @@ namespace MediaBrowser.Model.Dto
         public bool RequiresOpening { get; set; }
         public string OpenToken { get; set; }
         public bool RequiresClosing { get; set; }
+        public bool SupportsProbing { get; set; }
         public string LiveStreamId { get; set; }
         public int? BufferMs { get; set; }
 
@@ -63,6 +64,7 @@ namespace MediaBrowser.Model.Dto
             SupportsTranscoding = true;
             SupportsDirectStream = true;
             SupportsDirectPlay = true;
+            SupportsProbing = true;
         }
 
         public int? DefaultAudioStreamIndex { get; set; }

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

@@ -16,6 +16,7 @@ namespace MediaBrowser.Model.LiveTv
         public string RecordingEncodingFormat { get; set; }
         public bool EnableRecordingSubfolders { get; set; }
         public bool EnableOriginalAudioWithEncodedRecordings { get; set; }
+        public bool EnableOriginalVideoWithEncodedRecordings { get; set; }
 
         public List<TunerHostInfo> TunerHosts { get; set; }
         public List<ListingsProviderInfo> ListingProviders { get; set; }

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

@@ -42,6 +42,7 @@ namespace MediaBrowser.Model.LiveTv
         /// <value>The user identifier.</value>
         public string UserId { get; set; }
         public string SeriesTimerId { get; set; }
+        public string Name { get; set; }
 
         /// <summary>
         /// The earliest date for which a program starts to return

+ 2 - 0
MediaBrowser.Model/MediaInfo/LiveStreamRequest.cs

@@ -11,6 +11,7 @@ namespace MediaBrowser.Model.MediaInfo
         public long? StartTimeTicks { get; set; }
         public int? AudioStreamIndex { get; set; }
         public int? SubtitleStreamIndex { get; set; }
+        public int? MaxAudioChannels { get; set; }
         public string ItemId { get; set; }
         public DeviceProfile DeviceProfile { get; set; }
 
@@ -24,6 +25,7 @@ namespace MediaBrowser.Model.MediaInfo
             MaxStreamingBitrate = options.MaxBitrate;
             ItemId = options.ItemId;
             DeviceProfile = options.Profile;
+            MaxAudioChannels = options.MaxAudioChannels;
 
             VideoOptions videoOptions = options as VideoOptions;
             if (videoOptions != null)

+ 2 - 0
MediaBrowser.Model/MediaInfo/PlaybackInfoRequest.cs

@@ -16,6 +16,8 @@ namespace MediaBrowser.Model.MediaInfo
 
         public int? SubtitleStreamIndex { get; set; }
 
+        public int? MaxAudioChannels { get; set; }
+
         public string MediaSourceId { get; set; }
 
         public string LiveStreamId { get; set; }

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

@@ -100,6 +100,7 @@ namespace MediaBrowser.Model.Net
                 .ToDictionary(x => x.Key, x => x.First().Key, StringComparer.OrdinalIgnoreCase);
 
             dict["image/jpg"] = ".jpg";
+            dict["image/x-png"] = ".png";
 
             return dict;
         }

+ 8 - 3
MediaBrowser.Providers/Manager/ImageSaver.cs

@@ -72,7 +72,7 @@ namespace MediaBrowser.Providers.Manager
             return SaveImage(item, source, mimeType, type, imageIndex, null, cancellationToken);
         }
 
-        public async Task SaveImage(IHasImages item, Stream source, string mimeType, ImageType type, int? imageIndex, string internalCacheKey, CancellationToken cancellationToken)
+        public async Task SaveImage(IHasImages item, Stream source, string mimeType, ImageType type, int? imageIndex, bool? saveLocallyWithMedia, CancellationToken cancellationToken)
         {
             if (string.IsNullOrEmpty(mimeType))
             {
@@ -109,9 +109,9 @@ namespace MediaBrowser.Providers.Manager
                     }
                 }
             }
-            if (!string.IsNullOrEmpty(internalCacheKey))
+            if (saveLocallyWithMedia.HasValue && !saveLocallyWithMedia.Value)
             {
-                saveLocally = false;
+                saveLocally = saveLocallyWithMedia.Value;
             }
 
             if (!imageIndex.HasValue && item.AllowsMultipleImages(type))
@@ -356,6 +356,11 @@ namespace MediaBrowser.Providers.Manager
             var season = item as Season;
             var extension = MimeTypes.ToExtension(mimeType);
 
+            if (string.IsNullOrWhiteSpace(extension))
+            {
+                throw new ArgumentException(string.Format("Unable to determine image file extension from mime type {0}", mimeType));
+            }
+
             if (type == ImageType.Thumb && saveLocally)
             {
                 if (season != null && season.IndexNumber.HasValue)

+ 2 - 2
MediaBrowser.Providers/Manager/ItemImageProvider.cs

@@ -156,14 +156,14 @@ namespace MediaBrowser.Providers.Manager
 
                                     var stream = _fileSystem.GetFileStream(response.Path, FileMode.Open, FileAccess.Read, FileShare.Read, true);
 
-                                    await _providerManager.SaveImage(item, stream, mimeType, imageType, null, response.InternalCacheKey, cancellationToken).ConfigureAwait(false);
+                                    await _providerManager.SaveImage(item, stream, mimeType, imageType, null, cancellationToken).ConfigureAwait(false);
                                 }
                             }
                             else
                             {
                                 var mimeType = "image/" + response.Format.ToString().ToLower();
 
-                                await _providerManager.SaveImage(item, response.Stream, mimeType, imageType, null, response.InternalCacheKey, cancellationToken).ConfigureAwait(false);
+                                await _providerManager.SaveImage(item, response.Stream, mimeType, imageType, null, cancellationToken).ConfigureAwait(false);
                             }
 
                             downloadedImages.Add(imageType);

+ 8 - 11
MediaBrowser.Providers/Manager/MetadataService.cs

@@ -353,19 +353,16 @@ namespace MediaBrowser.Providers.Manager
         {
             var updateType = ItemUpdateType.None;
 
-            if (isFullRefresh || currentUpdateType > ItemUpdateType.None)
+            var folder = item as Folder;
+            if (folder != null && folder.SupportsDateLastMediaAdded)
             {
-                var folder = item as Folder;
-                if (folder != null && folder.SupportsDateLastMediaAdded)
-                {
-                    var items = folder.GetRecursiveChildren(i => !i.IsFolder).Select(i => i.DateCreated).ToList();
-                    var date = items.Count == 0 ? (DateTime?)null : items.Max();
+                var items = folder.GetRecursiveChildren(i => !i.IsFolder).Select(i => i.DateCreated).ToList();
+                var date = items.Count == 0 ? (DateTime?)null : items.Max();
 
-                    if ((!folder.DateLastMediaAdded.HasValue && date.HasValue) || folder.DateLastMediaAdded != date)
-                    {
-                        folder.DateLastMediaAdded = date;
-                        updateType = ItemUpdateType.MetadataEdit;
-                    }
+                if ((!folder.DateLastMediaAdded.HasValue && date.HasValue) || folder.DateLastMediaAdded != date)
+                {
+                    folder.DateLastMediaAdded = date;
+                    updateType = ItemUpdateType.MetadataImport;
                 }
             }
 

+ 2 - 7
MediaBrowser.Providers/Manager/ProviderManager.cs

@@ -140,12 +140,7 @@ namespace MediaBrowser.Providers.Manager
             return new ImageSaver(ConfigurationManager, _libraryMonitor, _fileSystem, _logger, _memoryStreamProvider).SaveImage(item, source, mimeType, type, imageIndex, cancellationToken);
         }
 
-        public Task SaveImage(IHasImages item, Stream source, string mimeType, ImageType type, int? imageIndex, string internalCacheKey, CancellationToken cancellationToken)
-        {
-            return new ImageSaver(ConfigurationManager, _libraryMonitor, _fileSystem, _logger, _memoryStreamProvider).SaveImage(item, source, mimeType, type, imageIndex, internalCacheKey, cancellationToken);
-        }
-
-        public Task SaveImage(IHasImages item, string source, string mimeType, ImageType type, int? imageIndex, string internalCacheKey, CancellationToken cancellationToken)
+        public Task SaveImage(IHasImages item, string source, string mimeType, ImageType type, int? imageIndex, bool? saveLocallyWithMedia, CancellationToken cancellationToken)
         {
             if (string.IsNullOrWhiteSpace(source))
             {
@@ -154,7 +149,7 @@ namespace MediaBrowser.Providers.Manager
 
             var fileStream = _fileSystem.GetFileStream(source, FileMode.Open, FileAccess.Read, FileShare.ReadWrite, true);
 
-            return new ImageSaver(ConfigurationManager, _libraryMonitor, _fileSystem, _logger, _memoryStreamProvider).SaveImage(item, fileStream, mimeType, type, imageIndex, internalCacheKey, cancellationToken);
+            return new ImageSaver(ConfigurationManager, _libraryMonitor, _fileSystem, _logger, _memoryStreamProvider).SaveImage(item, fileStream, mimeType, type, imageIndex, saveLocallyWithMedia, cancellationToken);
         }
 
         public async Task<IEnumerable<RemoteImageInfo>> GetAvailableRemoteImages(IHasImages item, RemoteImageQuery query, CancellationToken cancellationToken)

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

@@ -236,15 +236,9 @@ namespace MediaBrowser.Providers.Manager
 
         private static void MergeShortOverview(BaseItem source, BaseItem target, List<MetadataFields> lockedFields, bool replaceData)
         {
-            var sourceHasShortOverview = source as IHasShortOverview;
-            var targetHasShortOverview = target as IHasShortOverview;
-
-            if (sourceHasShortOverview != null && targetHasShortOverview != null)
+            if (replaceData || string.IsNullOrEmpty(target.ShortOverview))
             {
-                if (replaceData || string.IsNullOrEmpty(targetHasShortOverview.ShortOverview))
-                {
-                    targetHasShortOverview.ShortOverview = sourceHasShortOverview.ShortOverview;
-                }
+                target.ShortOverview = source.ShortOverview;
             }
         }
 
@@ -311,20 +305,14 @@ namespace MediaBrowser.Providers.Manager
 
         private static void MergeCriticRating(BaseItem source, BaseItem target, List<MetadataFields> lockedFields, bool replaceData)
         {
-            var sourceCast = source as IHasCriticRating;
-            var targetCast = target as IHasCriticRating;
-
-            if (sourceCast != null && targetCast != null)
+            if (replaceData || !target.CriticRating.HasValue)
             {
-                if (replaceData || !targetCast.CriticRating.HasValue)
-                {
-                    targetCast.CriticRating = sourceCast.CriticRating;
-                }
+                target.CriticRating = source.CriticRating;
+            }
 
-                if (replaceData || string.IsNullOrEmpty(targetCast.CriticRatingSummary))
-                {
-                    targetCast.CriticRatingSummary = sourceCast.CriticRatingSummary;
-                }
+            if (replaceData || string.IsNullOrEmpty(target.CriticRatingSummary))
+            {
+                target.CriticRatingSummary = source.CriticRatingSummary;
             }
         }
 

+ 30 - 42
MediaBrowser.Providers/Omdb/OmdbProvider.cs

@@ -66,28 +66,24 @@ namespace MediaBrowser.Providers.Omdb
                     item.ProductionYear = year;
                 }
 
-                var hasCriticRating = item as IHasCriticRating;
-                if (hasCriticRating != null)
-                {
-                    // Seeing some bogus RT data on omdb for series, so filter it out here
-                    // RT doesn't even have tv series
-                    int tomatoMeter;
+            // Seeing some bogus RT data on omdb for series, so filter it out here
+            // RT doesn't even have tv series
+            int tomatoMeter;
 
-                    if (!string.IsNullOrEmpty(result.tomatoMeter)
-                        && int.TryParse(result.tomatoMeter, NumberStyles.Integer, _usCulture, out tomatoMeter)
-                        && tomatoMeter >= 0)
-                    {
-                        hasCriticRating.CriticRating = tomatoMeter;
-                    }
+            if (!string.IsNullOrEmpty(result.tomatoMeter)
+                && int.TryParse(result.tomatoMeter, NumberStyles.Integer, _usCulture, out tomatoMeter)
+                && tomatoMeter >= 0)
+            {
+                item.CriticRating = tomatoMeter;
+            }
 
-                    if (!string.IsNullOrEmpty(result.tomatoConsensus)
-                        && !string.Equals(result.tomatoConsensus, "No consensus yet.", StringComparison.OrdinalIgnoreCase))
-                    {
-                        hasCriticRating.CriticRatingSummary = WebUtility.HtmlDecode(result.tomatoConsensus);
-                    }
-                }
+            if (!string.IsNullOrEmpty(result.tomatoConsensus)
+                && !string.Equals(result.tomatoConsensus, "No consensus yet.", StringComparison.OrdinalIgnoreCase))
+            {
+                item.CriticRatingSummary = WebUtility.HtmlDecode(result.tomatoConsensus);
+            }
 
-                int voteCount;
+            int voteCount;
 
                 if (!string.IsNullOrEmpty(result.imdbVotes)
                     && int.TryParse(result.imdbVotes, NumberStyles.Number, _usCulture, out voteCount)
@@ -167,25 +163,21 @@ namespace MediaBrowser.Providers.Omdb
                 item.ProductionYear = year;
             }
 
-            var hasCriticRating = item as IHasCriticRating;
-            if (hasCriticRating != null)
-            {
-                // Seeing some bogus RT data on omdb for series, so filter it out here
-                // RT doesn't even have tv series
-                int tomatoMeter;
+            // Seeing some bogus RT data on omdb for series, so filter it out here
+            // RT doesn't even have tv series
+            int tomatoMeter;
 
-                if (!string.IsNullOrEmpty(result.tomatoMeter)
-                    && int.TryParse(result.tomatoMeter, NumberStyles.Integer, _usCulture, out tomatoMeter)
-                    && tomatoMeter >= 0)
-                {
-                    hasCriticRating.CriticRating = tomatoMeter;
-                }
+            if (!string.IsNullOrEmpty(result.tomatoMeter)
+                && int.TryParse(result.tomatoMeter, NumberStyles.Integer, _usCulture, out tomatoMeter)
+                && tomatoMeter >= 0)
+            {
+                item.CriticRating = tomatoMeter;
+            }
 
-                if (!string.IsNullOrEmpty(result.tomatoConsensus)
-                    && !string.Equals(result.tomatoConsensus, "No consensus yet.", StringComparison.OrdinalIgnoreCase))
-                {
-                    hasCriticRating.CriticRatingSummary = WebUtility.HtmlDecode(result.tomatoConsensus);
-                }
+            if (!string.IsNullOrEmpty(result.tomatoConsensus)
+                && !string.Equals(result.tomatoConsensus, "No consensus yet.", StringComparison.OrdinalIgnoreCase))
+            {
+                item.CriticRatingSummary = WebUtility.HtmlDecode(result.tomatoConsensus);
             }
 
             int voteCount;
@@ -420,12 +412,8 @@ namespace MediaBrowser.Providers.Omdb
                 hasAwards.AwardSummary = WebUtility.HtmlDecode(result.Awards);
             }
 
-            var hasShortOverview = item as IHasShortOverview;
-            if (hasShortOverview != null)
-            {
-                // Imdb plots are usually pretty short
-                hasShortOverview.ShortOverview = result.Plot;
-            }
+            // Imdb plots are usually pretty short
+            item.ShortOverview = result.Plot;
 
             //if (!string.IsNullOrWhiteSpace(result.Director))
             //{

+ 10 - 0
MediaBrowser.Server.Implementations/IO/FileRefresher.cs

@@ -45,6 +45,11 @@ namespace MediaBrowser.Server.Implementations.IO
 
         private void AddAffectedPath(string path)
         {
+            if (string.IsNullOrWhiteSpace(path))
+            {
+                throw new ArgumentNullException("path");
+            }
+
             if (!_affectedPaths.Contains(path, StringComparer.Ordinal))
             {
                 _affectedPaths.Add(path);
@@ -53,6 +58,11 @@ namespace MediaBrowser.Server.Implementations.IO
 
         public void AddPath(string path)
         {
+            if (string.IsNullOrWhiteSpace(path))
+            {
+                throw new ArgumentNullException("path");
+            }
+
             lock (_timerLock)
             {
                 AddAffectedPath(path);

+ 6 - 2
MediaBrowser.Server.Implementations/Library/LibraryManager.cs

@@ -2838,9 +2838,13 @@ namespace MediaBrowser.Server.Implementations.Library
 
         private bool ValidateNetworkPath(string path)
         {
-            if (Environment.OSVersion.Platform == PlatformID.Win32NT || !path.StartsWith("\\\\", StringComparison.OrdinalIgnoreCase))
+            if (Environment.OSVersion.Platform == PlatformID.Win32NT)
             {
-                return Directory.Exists(path);
+                // We can't validate protocol-based paths, so just allow them
+                if (path.IndexOf("://", StringComparison.OrdinalIgnoreCase) == -1)
+                {
+                    return Directory.Exists(path);
+                }
             }
 
             // Without native support for unc, we cannot validate this when running under mono

+ 0 - 1
MediaBrowser.Server.Implementations/Library/MediaSourceManager.cs

@@ -360,7 +360,6 @@ namespace MediaBrowser.Server.Implementations.Library
 
         public async Task<LiveStreamResponse> OpenLiveStream(LiveStreamRequest request, bool enableAutoClose, CancellationToken cancellationToken)
         {
-            enableAutoClose = false;
             await _liveStreamSemaphore.WaitAsync(cancellationToken).ConfigureAwait(false);
 
             try

+ 28 - 32
MediaBrowser.Server.Implementations/Library/Resolvers/Movies/MovieResolver.cs

@@ -207,14 +207,18 @@ namespace MediaBrowser.Server.Implementations.Library.Resolvers.Movies
             // Find movies with their own folders
             if (args.IsDirectory)
             {
+                var files = args.FileSystemChildren
+                    .Where(i => !LibraryManager.IgnoreFile(i, args.Parent))
+                    .ToList();
+
                 if (string.Equals(collectionType, CollectionType.MusicVideos, StringComparison.OrdinalIgnoreCase))
                 {
-                    return null;
+                    return FindMovie<MusicVideo>(args.Path, args.Parent, files, args.DirectoryService, collectionType, false);
                 }
 
                 if (string.Equals(collectionType, CollectionType.HomeVideos, StringComparison.OrdinalIgnoreCase))
                 {
-                    return null;
+                    return FindMovie<Video>(args.Path, args.Parent, files, args.DirectoryService, collectionType, false);
                 }
 
                 if (string.IsNullOrEmpty(collectionType))
@@ -222,6 +226,7 @@ namespace MediaBrowser.Server.Implementations.Library.Resolvers.Movies
                     // Owned items will be caught by the plain video resolver
                     if (args.Parent == null)
                     {
+                        //return FindMovie<Video>(args.Path, args.Parent, files, args.DirectoryService, collectionType);
                         return null;
                     }
 
@@ -231,21 +236,13 @@ namespace MediaBrowser.Server.Implementations.Library.Resolvers.Movies
                     }
 
                     {
-                        var files = args.FileSystemChildren
-                            .Where(i => !LibraryManager.IgnoreFile(i, args.Parent))
-                            .ToList();
-
-                        return FindMovie<Movie>(args.Path, args.Parent, files, args.DirectoryService, collectionType);
+                        return FindMovie<Movie>(args.Path, args.Parent, files, args.DirectoryService, collectionType, true);
                     }
                 }
 
                 if (string.Equals(collectionType, CollectionType.Movies, StringComparison.OrdinalIgnoreCase))
                 {
-                    var files = args.FileSystemChildren
-                        .Where(i => !LibraryManager.IgnoreFile(i, args.Parent))
-                        .ToList();
-
-                    return FindMovie<Movie>(args.Path, args.Parent, files, args.DirectoryService, collectionType);
+                    return FindMovie<Movie>(args.Path, args.Parent, files, args.DirectoryService, collectionType, true);
                 }
 
                 return null;
@@ -360,13 +357,8 @@ namespace MediaBrowser.Server.Implementations.Library.Resolvers.Movies
         /// Finds a movie based on a child file system entries
         /// </summary>
         /// <typeparam name="T"></typeparam>
-        /// <param name="path">The path.</param>
-        /// <param name="parent">The parent.</param>
-        /// <param name="fileSystemEntries">The file system entries.</param>
-        /// <param name="directoryService">The directory service.</param>
-        /// <param name="collectionType">Type of the collection.</param>
         /// <returns>Movie.</returns>
-        private T FindMovie<T>(string path, Folder parent, List<FileSystemMetadata> fileSystemEntries, IDirectoryService directoryService, string collectionType)
+        private T FindMovie<T>(string path, Folder parent, List<FileSystemMetadata> fileSystemEntries, IDirectoryService directoryService, string collectionType, bool allowFilesAsFolders)
             where T : Video, new()
         {
             var multiDiscFolders = new List<FileSystemMetadata>();
@@ -413,23 +405,27 @@ namespace MediaBrowser.Server.Implementations.Library.Resolvers.Movies
                 }
             }
 
-            var supportsMultiVersion = !string.Equals(collectionType, CollectionType.HomeVideos) &&
-                                    !string.Equals(collectionType, CollectionType.Photos) &&
-                                    !string.Equals(collectionType, CollectionType.MusicVideos);
+            if (allowFilesAsFolders)
+            {
+                // TODO: Allow GetMultiDiscMovie in here
+                var supportsMultiVersion = !string.Equals(collectionType, CollectionType.HomeVideos) &&
+                                        !string.Equals(collectionType, CollectionType.Photos) &&
+                                        !string.Equals(collectionType, CollectionType.MusicVideos);
 
-            var result = ResolveVideos<T>(parent, fileSystemEntries, directoryService, supportsMultiVersion);
+                var result = ResolveVideos<T>(parent, fileSystemEntries, directoryService, supportsMultiVersion);
 
-            if (result.Items.Count == 1)
-            {
-                var movie = (T)result.Items[0];
-                movie.IsInMixedFolder = false;
-                movie.Name = Path.GetFileName(movie.ContainingFolderPath);
-                return movie;
-            }
+                if (result.Items.Count == 1)
+                {
+                    var movie = (T)result.Items[0];
+                    movie.IsInMixedFolder = false;
+                    movie.Name = Path.GetFileName(movie.ContainingFolderPath);
+                    return movie;
+                }
 
-            if (result.Items.Count == 0 && multiDiscFolders.Count > 0)
-            {
-                return GetMultiDiscMovie<T>(multiDiscFolders, directoryService);
+                if (result.Items.Count == 0 && multiDiscFolders.Count > 0)
+                {
+                    return GetMultiDiscMovie<T>(multiDiscFolders, directoryService);
+                }
             }
 
             return null;

+ 2 - 18
MediaBrowser.Server.Implementations/LiveTv/EmbyTV/EmbyTV.cs

@@ -1021,7 +1021,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv.EmbyTV
             {
                 var stream = new MediaSourceInfo
                 {
-                    Path = _appHost.GetLocalApiUrl("localhost") + "/LiveTv/LiveRecordings/" + recordingId + "/stream",
+                    Path = _appHost.GetLocalApiUrl("127.0.0.1") + "/LiveTv/LiveRecordings/" + recordingId + "/stream",
                     Id = recordingId,
                     SupportsDirectPlay = false,
                     SupportsDirectStream = true,
@@ -1854,23 +1854,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv.EmbyTV
                         ParentIndexNumber = program.SeasonNumber.Value,
                         IndexNumber = program.EpisodeNumber.Value,
                         AncestorIds = seriesIds,
-                        ExcludeLocationTypes = new[] { LocationType.Virtual }
-                    });
-
-                    if (result.TotalRecordCount > 0)
-                    {
-                        return true;
-                    }
-                }
-
-                if (!string.IsNullOrWhiteSpace(program.EpisodeTitle))
-                {
-                    var result = _libraryManager.GetItemsResult(new InternalItemsQuery
-                    {
-                        IncludeItemTypes = new[] { typeof(Episode).Name },
-                        Name = program.EpisodeTitle,
-                        AncestorIds = seriesIds,
-                        ExcludeLocationTypes = new[] { LocationType.Virtual }
+                        IsVirtualItem = false
                     });
 
                     if (result.TotalRecordCount > 0)

+ 6 - 1
MediaBrowser.Server.Implementations/LiveTv/EmbyTV/EncodedRecorder.cs

@@ -52,7 +52,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv.EmbyTV
             {
                 var format = _liveTvOptions.RecordingEncodingFormat;
 
-                if (string.Equals(format, "mkv", StringComparison.OrdinalIgnoreCase))
+                if (string.Equals(format, "mkv", StringComparison.OrdinalIgnoreCase) || _liveTvOptions.EnableOriginalVideoWithEncodedRecordings)
                 {
                     return "mkv";
                 }
@@ -204,6 +204,11 @@ namespace MediaBrowser.Server.Implementations.LiveTv.EmbyTV
 
         private bool EncodeVideo(MediaSourceInfo mediaSource)
         {
+            if (_liveTvOptions.EnableOriginalAudioWithEncodedRecordings)
+            {
+                return false;
+            }
+
             var mediaStreams = mediaSource.MediaStreams ?? new List<MediaStream>();
             return !mediaStreams.Any(i => i.Type == MediaStreamType.Video && string.Equals(i.Codec, "h264", StringComparison.OrdinalIgnoreCase) && !i.IsInterlaced);
         }

+ 5 - 1
MediaBrowser.Server.Implementations/LiveTv/LiveTvDtoService.cs

@@ -72,7 +72,11 @@ namespace MediaBrowser.Server.Implementations.LiveTv
             {
                 dto.ProgramInfo = _dtoService.GetBaseItemDto(program, new DtoOptions());
 
-                dto.ProgramInfo.TimerId = dto.Id;
+                if (info.Status != RecordingStatus.Cancelled && info.Status != RecordingStatus.Error)
+                {
+                    dto.ProgramInfo.TimerId = dto.Id;
+                    dto.ProgramInfo.Status = info.Status.ToString();
+                }
 
                 dto.ProgramInfo.SeriesTimerId = dto.SeriesTimerId;
             }

+ 2 - 2
MediaBrowser.Server.Implementations/LiveTv/LiveTvManager.cs

@@ -877,6 +877,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv
                 SortOrder = query.SortOrder ?? SortOrder.Ascending,
                 EnableTotalRecordCount = query.EnableTotalRecordCount,
                 TopParentIds = new[] { topFolder.Id.ToString("N") },
+                Name = query.Name,
                 DtoOptions = options
             };
 
@@ -1946,7 +1947,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv
                 }
                 else
                 {
-                    timers = timers.Where(i => !(i.Item1.Status == RecordingStatus.New));
+                    timers = timers.Where(i => i.Item1.Status != RecordingStatus.New);
                 }
             }
 
@@ -2304,7 +2305,6 @@ namespace MediaBrowser.Server.Implementations.LiveTv
 
             var info = await service.GetNewTimerDefaultsAsync(cancellationToken, programInfo).ConfigureAwait(false);
 
-            info.RecordAnyChannel = true;
             info.RecordAnyTime = true;
             info.Days = new List<DayOfWeek>
             {

+ 1 - 1
MediaBrowser.Server.Implementations/LiveTv/LiveTvMediaSourceProvider.cs

@@ -140,7 +140,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv
 
             try
             {
-                if (stream.MediaStreams.Any(i => i.Index != -1))
+                if (!stream.SupportsProbing || stream.MediaStreams.Any(i => i.Index != -1))
                 {
                     await AddMediaInfo(stream, isAudio, cancellationToken).ConfigureAwait(false);
                 }

+ 1 - 1
MediaBrowser.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunLiveStream.cs

@@ -60,7 +60,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv.TunerHosts.HdHomerun
             //OpenedMediaSource.Path = tempFile;
             //OpenedMediaSource.ReadAtNativeFramerate = true;
 
-            OpenedMediaSource.Path = _appHost.GetLocalApiUrl("localhost") + "/LiveTv/LiveStreamFiles/" + UniqueId + "/stream.ts";
+            OpenedMediaSource.Path = _appHost.GetLocalApiUrl("127.0.0.1") + "/LiveTv/LiveStreamFiles/" + UniqueId + "/stream.ts";
             OpenedMediaSource.Protocol = MediaProtocol.Http;
             OpenedMediaSource.SupportsDirectPlay = false;
             OpenedMediaSource.SupportsDirectStream = true;

+ 6 - 3
MediaBrowser.Server.Implementations/LiveTv/TunerHosts/M3UTunerHost.cs

@@ -13,6 +13,7 @@ using System.Threading;
 using System.Threading.Tasks;
 using CommonIO;
 using MediaBrowser.Common.Net;
+using MediaBrowser.Controller;
 using MediaBrowser.Controller.Configuration;
 using MediaBrowser.Controller.MediaEncoding;
 using MediaBrowser.Model.Serialization;
@@ -24,12 +25,14 @@ namespace MediaBrowser.Server.Implementations.LiveTv.TunerHosts
     {
         private readonly IFileSystem _fileSystem;
         private readonly IHttpClient _httpClient;
+        private readonly IServerApplicationHost _appHost;
 
-        public M3UTunerHost(IServerConfigurationManager config, ILogger logger, IJsonSerializer jsonSerializer, IMediaEncoder mediaEncoder, IFileSystem fileSystem, IHttpClient httpClient)
+        public M3UTunerHost(IServerConfigurationManager config, ILogger logger, IJsonSerializer jsonSerializer, IMediaEncoder mediaEncoder, IFileSystem fileSystem, IHttpClient httpClient, IServerApplicationHost appHost)
             : base(config, logger, jsonSerializer, mediaEncoder)
         {
             _fileSystem = fileSystem;
             _httpClient = httpClient;
+            _appHost = appHost;
         }
 
         public override string Type
@@ -46,7 +49,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv.TunerHosts
 
         protected override async Task<IEnumerable<ChannelInfo>> GetChannelsInternal(TunerHostInfo info, CancellationToken cancellationToken)
         {
-            return await new M3uParser(Logger, _fileSystem, _httpClient).Parse(info.Url, ChannelIdPrefix, info.Id, cancellationToken).ConfigureAwait(false);
+            return await new M3uParser(Logger, _fileSystem, _httpClient, _appHost).Parse(info.Url, ChannelIdPrefix, info.Id, cancellationToken).ConfigureAwait(false);
         }
 
         public Task<List<LiveTvTunerInfo>> GetTunerInfos(CancellationToken cancellationToken)
@@ -75,7 +78,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv.TunerHosts
 
         public async Task Validate(TunerHostInfo info)
         {
-            using (var stream = await new M3uParser(Logger, _fileSystem, _httpClient).GetListingsStream(info.Url, CancellationToken.None).ConfigureAwait(false))
+            using (var stream = await new M3uParser(Logger, _fileSystem, _httpClient, _appHost).GetListingsStream(info.Url, CancellationToken.None).ConfigureAwait(false))
             {
 
             }

+ 34 - 9
MediaBrowser.Server.Implementations/LiveTv/TunerHosts/M3uParser.cs

@@ -8,6 +8,7 @@ using System.Threading.Tasks;
 using CommonIO;
 using MediaBrowser.Common.Extensions;
 using MediaBrowser.Common.Net;
+using MediaBrowser.Controller;
 using MediaBrowser.Controller.LiveTv;
 using MediaBrowser.Model.Logging;
 
@@ -18,12 +19,14 @@ namespace MediaBrowser.Server.Implementations.LiveTv.TunerHosts
         private readonly ILogger _logger;
         private readonly IFileSystem _fileSystem;
         private readonly IHttpClient _httpClient;
+        private readonly IServerApplicationHost _appHost;
 
-        public M3uParser(ILogger logger, IFileSystem fileSystem, IHttpClient httpClient)
+        public M3uParser(ILogger logger, IFileSystem fileSystem, IHttpClient httpClient, IServerApplicationHost appHost)
         {
             _logger = logger;
             _fileSystem = fileSystem;
             _httpClient = httpClient;
+            _appHost = appHost;
         }
 
         public async Task<List<M3UChannel>> Parse(string url, string channelIdPrefix, string tunerHostId, CancellationToken cancellationToken)
@@ -41,7 +44,13 @@ namespace MediaBrowser.Server.Implementations.LiveTv.TunerHosts
         {
             if (url.StartsWith("http", StringComparison.OrdinalIgnoreCase))
             {
-                return _httpClient.Get(url, cancellationToken);
+                return _httpClient.Get(new HttpRequestOptions
+                {
+                    Url = url,
+                    CancellationToken = cancellationToken,
+                    // Some data providers will require a user agent
+                    UserAgent = _appHost.FriendlyName + "/" + _appHost.ApplicationVersion
+                });
             }
             return Task.FromResult(_fileSystem.OpenRead(url));
         }
@@ -111,15 +120,31 @@ namespace MediaBrowser.Server.Implementations.LiveTv.TunerHosts
                 channel.Number = "0";
             }
 
-            channel.ImageUrl = FindProperty("tvg-logo", extInf, null);
-            channel.Number = FindProperty("channel-id", extInf, channel.Number);
-            channel.Number = FindProperty("tvg-id", extInf, channel.Number);
-            channel.Name = FindProperty("tvg-id", extInf, channel.Name);
-            channel.Name = FindProperty("tvg-name", extInf, channel.Name);
+            channel.ImageUrl = FindProperty("tvg-logo", extInf);
+
+            var name = FindProperty("tvg-name", extInf);
+            if (string.IsNullOrWhiteSpace(name))
+            {
+                 name = FindProperty("tvg-id", extInf);
+            }
+
+            channel.Name = name;
+
+            var numberString = FindProperty("tvg-id", extInf);
+            if (string.IsNullOrWhiteSpace(numberString))
+            {
+                numberString = FindProperty("channel-id", extInf);
+            }
+
+            if (!string.IsNullOrWhiteSpace(numberString))
+            {
+                channel.Number = numberString;
+            }
+
             return channel;
 
         }
-        private string FindProperty(string property, string properties, string defaultResult = "")
+        private string FindProperty(string property, string properties)
         {
             var reg = new Regex(@"([a-z0-9\-_]+)=\""([^""]+)\""", RegexOptions.IgnoreCase);
             var matches = reg.Matches(properties);
@@ -130,7 +155,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv.TunerHosts
                     return match.Groups[2].Value;
                 }
             }
-            return defaultResult;
+            return null;
         }
     }
 

+ 5 - 2
MediaBrowser.Server.Implementations/LiveTv/TunerHosts/SatIp/SatIpHost.cs

@@ -8,6 +8,7 @@ using CommonIO;
 using MediaBrowser.Common.Configuration;
 using MediaBrowser.Common.Extensions;
 using MediaBrowser.Common.Net;
+using MediaBrowser.Controller;
 using MediaBrowser.Controller.Configuration;
 using MediaBrowser.Controller.LiveTv;
 using MediaBrowser.Controller.MediaEncoding;
@@ -25,12 +26,14 @@ namespace MediaBrowser.Server.Implementations.LiveTv.TunerHosts.SatIp
     {
         private readonly IFileSystem _fileSystem;
         private readonly IHttpClient _httpClient;
+        private readonly IServerApplicationHost _appHost;
 
-        public SatIpHost(IServerConfigurationManager config, ILogger logger, IJsonSerializer jsonSerializer, IMediaEncoder mediaEncoder, IFileSystem fileSystem, IHttpClient httpClient)
+        public SatIpHost(IServerConfigurationManager config, ILogger logger, IJsonSerializer jsonSerializer, IMediaEncoder mediaEncoder, IFileSystem fileSystem, IHttpClient httpClient, IServerApplicationHost appHost)
             : base(config, logger, jsonSerializer, mediaEncoder)
         {
             _fileSystem = fileSystem;
             _httpClient = httpClient;
+            _appHost = appHost;
         }
 
         private const string ChannelIdPrefix = "sat_";
@@ -39,7 +42,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv.TunerHosts.SatIp
         {
             if (!string.IsNullOrWhiteSpace(tuner.M3UUrl))
             {
-                return await new M3uParser(Logger, _fileSystem, _httpClient).Parse(tuner.M3UUrl, ChannelIdPrefix, tuner.Id, cancellationToken).ConfigureAwait(false);
+                return await new M3uParser(Logger, _fileSystem, _httpClient, _appHost).Parse(tuner.M3UUrl, ChannelIdPrefix, tuner.Id, cancellationToken).ConfigureAwait(false);
             }
 
             var channels = await new ChannelScan(Logger).Scan(tuner, cancellationToken).ConfigureAwait(false);

+ 1 - 1
MediaBrowser.Server.Implementations/Photos/BaseDynamicImageProvider.cs

@@ -144,7 +144,7 @@ namespace MediaBrowser.Server.Implementations.Photos
                 return ItemUpdateType.None;
             }
 
-            await ProviderManager.SaveImage(item, outputPath, "image/png", imageType, null, Guid.NewGuid().ToString("N"), cancellationToken).ConfigureAwait(false);
+            await ProviderManager.SaveImage(item, outputPath, "image/png", imageType, null, false, cancellationToken).ConfigureAwait(false);
 
             return ItemUpdateType.ImageUpdate;
         }

+ 1 - 3
MediaBrowser.Server.Implementations/Sorting/CriticRatingComparer.cs

@@ -22,9 +22,7 @@ namespace MediaBrowser.Server.Implementations.Sorting
 
         private float GetValue(BaseItem x)
         {
-            var hasCriticRating = x as IHasCriticRating;
-
-            return hasCriticRating == null ? 0 : hasCriticRating.CriticRating ?? 0;
+            return x.CriticRating ?? 0;
         }
 
         /// <summary>

+ 1 - 1
MediaBrowser.ServerApplication/MainStartup.cs

@@ -71,7 +71,7 @@ namespace MediaBrowser.ServerApplication
 
             if (_isRunningAsService)
             {
-                _canRestartService = CanRestartWindowsService();
+                //_canRestartService = CanRestartWindowsService();
             }
 
             var currentProcess = Process.GetCurrentProcess();

+ 0 - 6
MediaBrowser.WebDashboard/MediaBrowser.WebDashboard.csproj

@@ -986,9 +986,6 @@
     <Content Include="dashboard-ui\scripts\userparentalcontrol.js">
       <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
     </Content>
-    <Content Include="dashboard-ui\scripts\wizardservice.js">
-      <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
-    </Content>
     <Content Include="dashboard-ui\scripts\wizardsettings.js">
       <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
     </Content>
@@ -1034,9 +1031,6 @@
     <Content Include="dashboard-ui\wizardlivetvtuner.html">
       <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
     </Content>
-    <Content Include="dashboard-ui\wizardservice.html">
-      <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
-    </Content>
     <Content Include="dashboard-ui\wizardsettings.html">
       <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
     </Content>

+ 4 - 16
MediaBrowser.XbmcMetadata/Parsers/BaseNfoParser.cs

@@ -294,14 +294,12 @@ namespace MediaBrowser.XbmcMetadata.Parsers
                     {
                         var text = reader.ReadElementContentAsString();
 
-                        var hasCriticRating = item as IHasCriticRating;
-
-                        if (hasCriticRating != null && !string.IsNullOrEmpty(text))
+                        if (!string.IsNullOrEmpty(text))
                         {
                             float value;
                             if (float.TryParse(text, NumberStyles.Any, _usCulture, out value))
                             {
-                                hasCriticRating.CriticRating = value;
+                                item.CriticRating = value;
                             }
                         }
 
@@ -388,12 +386,7 @@ namespace MediaBrowser.XbmcMetadata.Parsers
 
                         if (!string.IsNullOrWhiteSpace(val))
                         {
-                            var hasShortOverview = item as IHasShortOverview;
-
-                            if (hasShortOverview != null)
-                            {
-                                hasShortOverview.ShortOverview = val;
-                            }
+                            item.ShortOverview = val;
                         }
                         break;
                     }
@@ -418,12 +411,7 @@ namespace MediaBrowser.XbmcMetadata.Parsers
 
                         if (!string.IsNullOrWhiteSpace(val))
                         {
-                            var hasCriticRating = item as IHasCriticRating;
-
-                            if (hasCriticRating != null)
-                            {
-                                hasCriticRating.CriticRatingSummary = val;
-                            }
+                            item.CriticRatingSummary = val;
                         }
 
                         break;

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

@@ -2,7 +2,7 @@
 <package xmlns="http://schemas.microsoft.com/packaging/2011/08/nuspec.xsd">
     <metadata>
         <id>MediaBrowser.Common.Internal</id>
-        <version>3.0.663</version>
+        <version>3.0.665</version>
         <title>MediaBrowser.Common.Internal</title>
         <authors>Luke</authors>
         <owners>ebr,Luke,scottisafool</owners>
@@ -12,7 +12,7 @@
         <description>Contains common components shared by Emby Theater and Emby Server. Not intended for plugin developer consumption.</description>
         <copyright>Copyright © Emby 2013</copyright>
         <dependencies>
-            <dependency id="MediaBrowser.Common" version="3.0.663" />
+            <dependency id="MediaBrowser.Common" version="3.0.665" />
             <dependency id="NLog" version="4.3.8" />
             <dependency id="SimpleInjector" version="3.2.2" />
         </dependencies>

+ 1 - 1
Nuget/MediaBrowser.Common.nuspec

@@ -2,7 +2,7 @@
 <package xmlns="http://schemas.microsoft.com/packaging/2011/08/nuspec.xsd">
     <metadata>
         <id>MediaBrowser.Common</id>
-        <version>3.0.663</version>
+        <version>3.0.665</version>
         <title>MediaBrowser.Common</title>
         <authors>Emby Team</authors>
         <owners>ebr,Luke,scottisafool</owners>

+ 2 - 2
Nuget/MediaBrowser.Server.Core.nuspec

@@ -2,7 +2,7 @@
 <package xmlns="http://schemas.microsoft.com/packaging/2010/07/nuspec.xsd">
     <metadata>
         <id>MediaBrowser.Server.Core</id>
-        <version>3.0.663</version>
+        <version>3.0.665</version>
         <title>Media Browser.Server.Core</title>
         <authors>Emby Team</authors>
         <owners>ebr,Luke,scottisafool</owners>
@@ -12,7 +12,7 @@
         <description>Contains core components required to build plugins for Emby Server.</description>
         <copyright>Copyright © Emby 2013</copyright>
         <dependencies>
-            <dependency id="MediaBrowser.Common" version="3.0.663" />
+            <dependency id="MediaBrowser.Common" version="3.0.665" />
 			<dependency id="Interfaces.IO" version="1.0.0.5" />
         </dependencies>
     </metadata>