diff --git a/MediaBrowser.Api/Playback/BaseStreamingService.cs b/MediaBrowser.Api/Playback/BaseStreamingService.cs index 7dcb06f7b3..f65949ac7d 100644 --- a/MediaBrowser.Api/Playback/BaseStreamingService.cs +++ b/MediaBrowser.Api/Playback/BaseStreamingService.cs @@ -1,6 +1,7 @@ using MediaBrowser.Common.Extensions; using MediaBrowser.Common.IO; using MediaBrowser.Controller.Configuration; +using MediaBrowser.Controller.Dlna; using MediaBrowser.Controller.Dto; using MediaBrowser.Controller.Entities; using MediaBrowser.Controller.Library; @@ -65,6 +66,7 @@ namespace MediaBrowser.Api.Playback protected IItemRepository ItemRepository { get; private set; } protected ILiveTvManager LiveTvManager { get; private set; } + protected IDlnaManager DlnaManager { get; private set; } /// /// Initializes a new instance of the class. @@ -77,8 +79,9 @@ namespace MediaBrowser.Api.Playback /// The dto service. /// The file system. /// The item repository. - protected BaseStreamingService(IServerConfigurationManager serverConfig, IUserManager userManager, ILibraryManager libraryManager, IIsoManager isoManager, IMediaEncoder mediaEncoder, IDtoService dtoService, IFileSystem fileSystem, IItemRepository itemRepository, ILiveTvManager liveTvManager, IEncodingManager encodingManager) + protected BaseStreamingService(IServerConfigurationManager serverConfig, IUserManager userManager, ILibraryManager libraryManager, IIsoManager isoManager, IMediaEncoder mediaEncoder, IDtoService dtoService, IFileSystem fileSystem, IItemRepository itemRepository, ILiveTvManager liveTvManager, IEncodingManager encodingManager, IDlnaManager dlnaManager) { + DlnaManager = dlnaManager; EncodingManager = encodingManager; LiveTvManager = liveTvManager; ItemRepository = itemRepository; @@ -774,29 +777,24 @@ namespace MediaBrowser.Api.Playback { var codec = request.AudioCodec; - if (!string.IsNullOrEmpty(codec)) + if (string.Equals(codec, "aac", StringComparison.OrdinalIgnoreCase)) { - if (string.Equals(codec, "aac", StringComparison.OrdinalIgnoreCase)) - { - return "aac -strict experimental"; - } - if (string.Equals(codec, "mp3", StringComparison.OrdinalIgnoreCase)) - { - return "libmp3lame"; - } - if (string.Equals(codec, "vorbis", StringComparison.OrdinalIgnoreCase)) - { - return "libvorbis"; - } - if (string.Equals(codec, "wma", StringComparison.OrdinalIgnoreCase)) - { - return "wmav2"; - } - - return codec.ToLower(); + return "aac -strict experimental"; + } + if (string.Equals(codec, "mp3", StringComparison.OrdinalIgnoreCase)) + { + return "libmp3lame"; + } + if (string.Equals(codec, "vorbis", StringComparison.OrdinalIgnoreCase)) + { + return "libvorbis"; + } + if (string.Equals(codec, "wma", StringComparison.OrdinalIgnoreCase)) + { + return "wmav2"; } - return "copy"; + return codec.ToLower(); } /// @@ -1212,96 +1210,85 @@ namespace MediaBrowser.Api.Playback if (i == 0) { - // Device profile name + request.DeviceId = val; } else if (i == 1) { - request.DeviceId = val; + request.MediaSourceId = val; } else if (i == 2) - { - request.MediaSourceId = val; - } - else if (i == 3) { request.Static = string.Equals("true", val, StringComparison.OrdinalIgnoreCase); } - else if (i == 4) + else if (i == 3) { if (videoRequest != null) { videoRequest.VideoCodec = val; } } - else if (i == 5) + else if (i == 4) { request.AudioCodec = val; } - else if (i == 6) + else if (i == 5) { if (videoRequest != null) { videoRequest.AudioStreamIndex = int.Parse(val, UsCulture); } } - else if (i == 7) + else if (i == 6) { if (videoRequest != null) { videoRequest.SubtitleStreamIndex = int.Parse(val, UsCulture); } } - else if (i == 8) + else if (i == 7) { if (videoRequest != null) { videoRequest.VideoBitRate = int.Parse(val, UsCulture); } } - else if (i == 9) + else if (i == 8) { request.AudioBitRate = int.Parse(val, UsCulture); } - else if (i == 10) + else if (i == 9) { request.MaxAudioChannels = int.Parse(val, UsCulture); } - else if (i == 11) + else if (i == 10) { if (videoRequest != null) { videoRequest.MaxWidth = int.Parse(val, UsCulture); } } - else if (i == 12) + else if (i == 11) { if (videoRequest != null) { videoRequest.MaxHeight = int.Parse(val, UsCulture); } } - else if (i == 13) + else if (i == 12) { if (videoRequest != null) { videoRequest.Framerate = int.Parse(val, UsCulture); } } - else if (i == 14) + else if (i == 13) { if (videoRequest != null) { request.StartTimeTicks = long.Parse(val, UsCulture); } } - else if (i == 15) - { - if (videoRequest != null) - { - videoRequest.Profile = val; - } - } - else if (i == 16) + else if (i == 14) { if (videoRequest != null) { @@ -1487,9 +1474,172 @@ namespace MediaBrowser.Api.Playback state.SegmentLength = state.ReadInputAtNativeFramerate ? 5 : 10; state.HlsListSize = state.ReadInputAtNativeFramerate ? 100 : 1440; + ApplyDeviceProfileSettings(state); + return state; } + private void ApplyDeviceProfileSettings(StreamState state) + { + var headers = new Dictionary(); + + foreach (var key in Request.Headers.AllKeys) + { + headers[key] = Request.Headers[key]; + } + + var profile = DlnaManager.GetProfile(headers); + + var container = Path.GetExtension(state.RequestedUrl); + + if (string.IsNullOrEmpty(container)) + { + container = Path.GetExtension(GetOutputFilePath(state)); + } + + var audioCodec = state.Request.AudioCodec; + + if (string.Equals(audioCodec, "copy", StringComparison.OrdinalIgnoreCase) && state.AudioStream != null) + { + audioCodec = state.AudioStream.Codec; + } + + var videoCodec = state.VideoRequest == null ? null : state.VideoRequest.VideoCodec; + + if (string.Equals(videoCodec, "copy", StringComparison.OrdinalIgnoreCase) && state.VideoStream != null) + { + videoCodec = state.VideoStream.Codec; + } + + var mediaProfile = state.VideoRequest == null ? + profile.GetAudioMediaProfile(container, audioCodec, state.AudioStream) : + profile.GetVideoMediaProfile(container, audioCodec, videoCodec, state.AudioStream, state.VideoStream); + + if (mediaProfile != null) + { + state.MimeType = mediaProfile.MimeType; + state.OrgPn = mediaProfile.OrgPn; + } + + var transcodingProfile = state.VideoRequest == null ? + profile.GetAudioTranscodingProfile(container, audioCodec) : + profile.GetVideoTranscodingProfile(container, audioCodec, videoCodec); + + if (transcodingProfile != null) + { + state.EstimateContentLength = transcodingProfile.EstimateContentLength; + state.EnableMpegtsM2TsMode = transcodingProfile.EnableMpegtsM2TsMode; + state.TranscodeSeekInfo = transcodingProfile.TranscodeSeekInfo; + + foreach (var setting in transcodingProfile.Settings) + { + switch (setting.Name) + { + case TranscodingSettingType.VideoProfile: + { + if (state.VideoRequest != null && string.IsNullOrWhiteSpace(state.VideoRequest.Profile)) + { + state.VideoRequest.Profile = setting.Value; + } + break; + } + default: + throw new ArgumentException("Unrecognized TranscodingSettingType"); + } + } + } + } + + + /// + /// Adds the dlna headers. + /// + /// The state. + /// The response headers. + /// if set to true [is statically streamed]. + /// true if XXXX, false otherwise + protected void AddDlnaHeaders(StreamState state, IDictionary responseHeaders, bool isStaticallyStreamed) + { + var timeSeek = GetHeader("TimeSeekRange.dlna.org"); + + if (!string.IsNullOrEmpty(timeSeek)) + { + ResultFactory.ThrowError(406, "Time seek not supported during encoding.", responseHeaders); + return; + } + + var transferMode = GetHeader("transferMode.dlna.org"); + responseHeaders["transferMode.dlna.org"] = string.IsNullOrEmpty(transferMode) ? "Streaming" : transferMode; + responseHeaders["realTimeInfo.dlna.org"] = "DLNA.ORG_TLAG=*"; + + var contentFeatures = string.Empty; + var extension = GetOutputFileExtension(state); + + // first bit means Time based seek supported, second byte range seek supported (not sure about the order now), so 01 = only byte seek, 10 = time based, 11 = both, 00 = none + var orgOp = isStaticallyStreamed || state.TranscodeSeekInfo == TranscodeSeekInfo.Bytes ? ";DLNA.ORG_OP=01" : ";DLNA.ORG_OP=00"; + + // 0 = native, 1 = transcoded + var orgCi = isStaticallyStreamed ? ";DLNA.ORG_CI=0" : ";DLNA.ORG_CI=1"; + + const string dlnaflags = ";DLNA.ORG_FLAGS=01500000000000000000000000000000"; + + if (!string.IsNullOrWhiteSpace(state.OrgPn)) + { + contentFeatures = "DLNA.ORG_PN=" + state.OrgPn; + } + else if (string.Equals(extension, ".mp3", StringComparison.OrdinalIgnoreCase)) + { + contentFeatures = "DLNA.ORG_PN=MP3"; + } + else if (string.Equals(extension, ".aac", StringComparison.OrdinalIgnoreCase)) + { + contentFeatures = "DLNA.ORG_PN=AAC_ISO"; + } + else if (string.Equals(extension, ".wma", StringComparison.OrdinalIgnoreCase)) + { + contentFeatures = "DLNA.ORG_PN=WMABASE"; + } + else if (string.Equals(extension, ".avi", StringComparison.OrdinalIgnoreCase)) + { + contentFeatures = "DLNA.ORG_PN=AVI"; + } + else if (string.Equals(extension, ".mkv", StringComparison.OrdinalIgnoreCase)) + { + contentFeatures = "DLNA.ORG_PN=MATROSKA"; + } + else if (string.Equals(extension, ".mp4", StringComparison.OrdinalIgnoreCase)) + { + contentFeatures = "DLNA.ORG_PN=AVC_MP4_MP_HD_720p_AAC"; + } + else if (string.Equals(extension, ".mpeg", StringComparison.OrdinalIgnoreCase)) + { + contentFeatures = "DLNA.ORG_PN=MPEG_PS_PAL"; + } + else if (string.Equals(extension, ".ts", StringComparison.OrdinalIgnoreCase)) + { + contentFeatures = "DLNA.ORG_PN=MPEG_PS_PAL"; + } + //else if (string.Equals(extension, ".wmv", StringComparison.OrdinalIgnoreCase)) + //{ + // contentFeatures = "DLNA.ORG_PN=WMVHIGH_BASE"; + //} + //else if (string.Equals(extension, ".asf", StringComparison.OrdinalIgnoreCase)) + //{ + // // ?? + // contentFeatures = "DLNA.ORG_PN=WMVHIGH_BASE"; + //} + + if (!string.IsNullOrEmpty(contentFeatures)) + { + responseHeaders["contentFeatures.dlna.org"] = (contentFeatures + orgOp + orgCi + dlnaflags).Trim(';'); + } + + foreach (var item in responseHeaders) + { + Request.Response.AddHeader(item.Key, item.Value); + } + } + /// /// Enforces the resolution limit. /// @@ -1605,7 +1755,7 @@ namespace MediaBrowser.Api.Playback return "vorbis"; } - return null; + return "copy"; } /// diff --git a/MediaBrowser.Api/Playback/Hls/BaseHlsService.cs b/MediaBrowser.Api/Playback/Hls/BaseHlsService.cs index eb8f415e0d..198376d6a1 100644 --- a/MediaBrowser.Api/Playback/Hls/BaseHlsService.cs +++ b/MediaBrowser.Api/Playback/Hls/BaseHlsService.cs @@ -2,13 +2,13 @@ using MediaBrowser.Common.IO; using MediaBrowser.Common.Net; using MediaBrowser.Controller.Configuration; +using MediaBrowser.Controller.Dlna; using MediaBrowser.Controller.Dto; using MediaBrowser.Controller.Library; using MediaBrowser.Controller.LiveTv; using MediaBrowser.Controller.MediaEncoding; using MediaBrowser.Controller.Persistence; using MediaBrowser.Model.Configuration; -using MediaBrowser.Model.Dto; using MediaBrowser.Model.IO; using System; using System.Collections.Generic; @@ -24,7 +24,7 @@ namespace MediaBrowser.Api.Playback.Hls /// public abstract class BaseHlsService : BaseStreamingService { - protected BaseHlsService(IServerConfigurationManager serverConfig, IUserManager userManager, ILibraryManager libraryManager, IIsoManager isoManager, IMediaEncoder mediaEncoder, IDtoService dtoService, IFileSystem fileSystem, IItemRepository itemRepository, ILiveTvManager liveTvManager, IEncodingManager encodingManager) : base(serverConfig, userManager, libraryManager, isoManager, mediaEncoder, dtoService, fileSystem, itemRepository, liveTvManager, encodingManager) + protected BaseHlsService(IServerConfigurationManager serverConfig, IUserManager userManager, ILibraryManager libraryManager, IIsoManager isoManager, IMediaEncoder mediaEncoder, IDtoService dtoService, IFileSystem fileSystem, IItemRepository itemRepository, ILiveTvManager liveTvManager, IEncodingManager encodingManager, IDlnaManager dlnaManager) : base(serverConfig, userManager, libraryManager, isoManager, mediaEncoder, dtoService, fileSystem, itemRepository, liveTvManager, encodingManager, dlnaManager) { } diff --git a/MediaBrowser.Api/Playback/Hls/DynamicHlsService.cs b/MediaBrowser.Api/Playback/Hls/DynamicHlsService.cs index 66e8b0d149..ab0cd8871f 100644 --- a/MediaBrowser.Api/Playback/Hls/DynamicHlsService.cs +++ b/MediaBrowser.Api/Playback/Hls/DynamicHlsService.cs @@ -1,12 +1,12 @@ using MediaBrowser.Common.Extensions; using MediaBrowser.Common.IO; using MediaBrowser.Controller.Configuration; +using MediaBrowser.Controller.Dlna; using MediaBrowser.Controller.Dto; using MediaBrowser.Controller.Library; using MediaBrowser.Controller.LiveTv; using MediaBrowser.Controller.MediaEncoding; using MediaBrowser.Controller.Persistence; -using MediaBrowser.Model.Dto; using MediaBrowser.Model.IO; using ServiceStack; using System; @@ -60,7 +60,7 @@ namespace MediaBrowser.Api.Playback.Hls public class DynamicHlsService : BaseHlsService { - public DynamicHlsService(IServerConfigurationManager serverConfig, IUserManager userManager, ILibraryManager libraryManager, IIsoManager isoManager, IMediaEncoder mediaEncoder, IDtoService dtoService, IFileSystem fileSystem, IItemRepository itemRepository, ILiveTvManager liveTvManager, IEncodingManager encodingManager) : base(serverConfig, userManager, libraryManager, isoManager, mediaEncoder, dtoService, fileSystem, itemRepository, liveTvManager, encodingManager) + public DynamicHlsService(IServerConfigurationManager serverConfig, IUserManager userManager, ILibraryManager libraryManager, IIsoManager isoManager, IMediaEncoder mediaEncoder, IDtoService dtoService, IFileSystem fileSystem, IItemRepository itemRepository, ILiveTvManager liveTvManager, IEncodingManager encodingManager, IDlnaManager dlnaManager) : base(serverConfig, userManager, libraryManager, isoManager, mediaEncoder, dtoService, fileSystem, itemRepository, liveTvManager, encodingManager, dlnaManager) { } diff --git a/MediaBrowser.Api/Playback/Hls/VideoHlsService.cs b/MediaBrowser.Api/Playback/Hls/VideoHlsService.cs index a2080995d0..1bca4cae9a 100644 --- a/MediaBrowser.Api/Playback/Hls/VideoHlsService.cs +++ b/MediaBrowser.Api/Playback/Hls/VideoHlsService.cs @@ -1,5 +1,6 @@ using MediaBrowser.Common.IO; using MediaBrowser.Controller.Configuration; +using MediaBrowser.Controller.Dlna; using MediaBrowser.Controller.Dto; using MediaBrowser.Controller.Library; using MediaBrowser.Controller.LiveTv; @@ -52,7 +53,7 @@ namespace MediaBrowser.Api.Playback.Hls /// public class VideoHlsService : BaseHlsService { - public VideoHlsService(IServerConfigurationManager serverConfig, IUserManager userManager, ILibraryManager libraryManager, IIsoManager isoManager, IMediaEncoder mediaEncoder, IDtoService dtoService, IFileSystem fileSystem, IItemRepository itemRepository, ILiveTvManager liveTvManager, IEncodingManager encodingManager) : base(serverConfig, userManager, libraryManager, isoManager, mediaEncoder, dtoService, fileSystem, itemRepository, liveTvManager, encodingManager) + public VideoHlsService(IServerConfigurationManager serverConfig, IUserManager userManager, ILibraryManager libraryManager, IIsoManager isoManager, IMediaEncoder mediaEncoder, IDtoService dtoService, IFileSystem fileSystem, IItemRepository itemRepository, ILiveTvManager liveTvManager, IEncodingManager encodingManager, IDlnaManager dlnaManager) : base(serverConfig, userManager, libraryManager, isoManager, mediaEncoder, dtoService, fileSystem, itemRepository, liveTvManager, encodingManager, dlnaManager) { } diff --git a/MediaBrowser.Api/Playback/Progressive/AudioService.cs b/MediaBrowser.Api/Playback/Progressive/AudioService.cs index 4d8d3a5816..ca206c0125 100644 --- a/MediaBrowser.Api/Playback/Progressive/AudioService.cs +++ b/MediaBrowser.Api/Playback/Progressive/AudioService.cs @@ -1,6 +1,7 @@ using MediaBrowser.Common.IO; using MediaBrowser.Common.Net; using MediaBrowser.Controller.Configuration; +using MediaBrowser.Controller.Dlna; using MediaBrowser.Controller.Drawing; using MediaBrowser.Controller.Dto; using MediaBrowser.Controller.Library; @@ -43,7 +44,7 @@ namespace MediaBrowser.Api.Playback.Progressive /// public class AudioService : BaseProgressiveStreamingService { - public AudioService(IServerConfigurationManager serverConfig, IUserManager userManager, ILibraryManager libraryManager, IIsoManager isoManager, IMediaEncoder mediaEncoder, IDtoService dtoService, IFileSystem fileSystem, IItemRepository itemRepository, ILiveTvManager liveTvManager, IEncodingManager encodingManager, IHttpClient httpClient, IImageProcessor imageProcessor) : base(serverConfig, userManager, libraryManager, isoManager, mediaEncoder, dtoService, fileSystem, itemRepository, liveTvManager, encodingManager, httpClient, imageProcessor) + public AudioService(IServerConfigurationManager serverConfig, IUserManager userManager, ILibraryManager libraryManager, IIsoManager isoManager, IMediaEncoder mediaEncoder, IDtoService dtoService, IFileSystem fileSystem, IItemRepository itemRepository, ILiveTvManager liveTvManager, IEncodingManager encodingManager, IDlnaManager dlnaManager, IHttpClient httpClient, IImageProcessor imageProcessor) : base(serverConfig, userManager, libraryManager, isoManager, mediaEncoder, dtoService, fileSystem, itemRepository, liveTvManager, encodingManager, dlnaManager, httpClient, imageProcessor) { } diff --git a/MediaBrowser.Api/Playback/Progressive/BaseProgressiveStreamingService.cs b/MediaBrowser.Api/Playback/Progressive/BaseProgressiveStreamingService.cs index 9cb989fc21..dad8a51bd7 100644 --- a/MediaBrowser.Api/Playback/Progressive/BaseProgressiveStreamingService.cs +++ b/MediaBrowser.Api/Playback/Progressive/BaseProgressiveStreamingService.cs @@ -1,13 +1,13 @@ using MediaBrowser.Common.IO; using MediaBrowser.Common.Net; using MediaBrowser.Controller.Configuration; +using MediaBrowser.Controller.Dlna; using MediaBrowser.Controller.Drawing; using MediaBrowser.Controller.Dto; using MediaBrowser.Controller.Library; using MediaBrowser.Controller.LiveTv; using MediaBrowser.Controller.MediaEncoding; using MediaBrowser.Controller.Persistence; -using MediaBrowser.Model.Dto; using MediaBrowser.Model.IO; using ServiceStack.Web; using System; @@ -26,8 +26,7 @@ namespace MediaBrowser.Api.Playback.Progressive protected readonly IImageProcessor ImageProcessor; protected readonly IHttpClient HttpClient; - protected BaseProgressiveStreamingService(IServerConfigurationManager serverConfig, IUserManager userManager, ILibraryManager libraryManager, IIsoManager isoManager, IMediaEncoder mediaEncoder, IDtoService dtoService, IFileSystem fileSystem, IItemRepository itemRepository, ILiveTvManager liveTvManager, IEncodingManager encodingManager, IHttpClient httpClient, IImageProcessor imageProcessor) - : base(serverConfig, userManager, libraryManager, isoManager, mediaEncoder, dtoService, fileSystem, itemRepository, liveTvManager, encodingManager) + protected BaseProgressiveStreamingService(IServerConfigurationManager serverConfig, IUserManager userManager, ILibraryManager libraryManager, IIsoManager isoManager, IMediaEncoder mediaEncoder, IDtoService dtoService, IFileSystem fileSystem, IItemRepository itemRepository, ILiveTvManager liveTvManager, IEncodingManager encodingManager, IDlnaManager dlnaManager, IHttpClient httpClient, IImageProcessor imageProcessor) : base(serverConfig, userManager, libraryManager, isoManager, mediaEncoder, dtoService, fileSystem, itemRepository, liveTvManager, encodingManager, dlnaManager) { HttpClient = httpClient; ImageProcessor = imageProcessor; @@ -100,92 +99,6 @@ namespace MediaBrowser.Api.Playback.Progressive return null; } - /// - /// Adds the dlna headers. - /// - /// The state. - /// The response headers. - /// if set to true [is statically streamed]. - /// true if XXXX, false otherwise - private void AddDlnaHeaders(StreamState state, IDictionary responseHeaders, bool isStaticallyStreamed) - { - var timeSeek = GetHeader("TimeSeekRange.dlna.org"); - - if (!string.IsNullOrEmpty(timeSeek)) - { - ResultFactory.ThrowError(406, "Time seek not supported during encoding.", responseHeaders); - return; - } - - var transferMode = GetHeader("transferMode.dlna.org"); - responseHeaders["transferMode.dlna.org"] = string.IsNullOrEmpty(transferMode) ? "Streaming" : transferMode; - responseHeaders["realTimeInfo.dlna.org"] = "DLNA.ORG_TLAG=*"; - - var contentFeatures = string.Empty; - var extension = GetOutputFileExtension(state); - - // first bit means Time based seek supported, second byte range seek supported (not sure about the order now), so 01 = only byte seek, 10 = time based, 11 = both, 00 = none - var orgOp = isStaticallyStreamed ? ";DLNA.ORG_OP=01" : ";DLNA.ORG_OP=00"; - - // 0 = native, 1 = transcoded - var orgCi = isStaticallyStreamed ? ";DLNA.ORG_CI=0" : ";DLNA.ORG_CI=1"; - - const string dlnaflags = ";DLNA.ORG_FLAGS=01500000000000000000000000000000"; - - if (string.Equals(extension, ".mp3", StringComparison.OrdinalIgnoreCase)) - { - contentFeatures = "DLNA.ORG_PN=MP3"; - } - else if (string.Equals(extension, ".aac", StringComparison.OrdinalIgnoreCase)) - { - contentFeatures = "DLNA.ORG_PN=AAC_ISO"; - } - else if (string.Equals(extension, ".wma", StringComparison.OrdinalIgnoreCase)) - { - contentFeatures = "DLNA.ORG_PN=WMABASE"; - } - else if (string.Equals(extension, ".avi", StringComparison.OrdinalIgnoreCase)) - { - contentFeatures = "DLNA.ORG_PN=AVI"; - } - else if (string.Equals(extension, ".mkv", StringComparison.OrdinalIgnoreCase)) - { - contentFeatures = "DLNA.ORG_PN=MATROSKA"; - } - else if (string.Equals(extension, ".mp4", StringComparison.OrdinalIgnoreCase)) - { - contentFeatures = "DLNA.ORG_PN=AVC_MP4_MP_HD_720p_AAC"; - } - else if (string.Equals(extension, ".mpeg", StringComparison.OrdinalIgnoreCase)) - { - contentFeatures = "DLNA.ORG_PN=MPEG_PS_PAL"; - } - else if (string.Equals(extension, ".ts", StringComparison.OrdinalIgnoreCase)) - { - contentFeatures = "DLNA.ORG_PN=MPEG_PS_PAL"; - } - //else if (string.Equals(extension, ".wmv", StringComparison.OrdinalIgnoreCase)) - //{ - // contentFeatures = "DLNA.ORG_PN=WMVHIGH_BASE"; - //} - //else if (string.Equals(extension, ".asf", StringComparison.OrdinalIgnoreCase)) - //{ - // // ?? - // contentFeatures = "DLNA.ORG_PN=WMVHIGH_BASE"; - //} - - - if (!string.IsNullOrEmpty(contentFeatures)) - { - responseHeaders["contentFeatures.dlna.org"] = (contentFeatures + orgOp + orgCi + dlnaflags).Trim(';'); - } - - foreach (var item in responseHeaders) - { - Request.Response.AddHeader(item.Key, item.Value); - } - } - /// /// Gets the type of the transcoding job. /// diff --git a/MediaBrowser.Api/Playback/Progressive/VideoService.cs b/MediaBrowser.Api/Playback/Progressive/VideoService.cs index 43dc6f0d49..0fc78f0e3d 100644 --- a/MediaBrowser.Api/Playback/Progressive/VideoService.cs +++ b/MediaBrowser.Api/Playback/Progressive/VideoService.cs @@ -1,6 +1,7 @@ using MediaBrowser.Common.IO; using MediaBrowser.Common.Net; using MediaBrowser.Controller.Configuration; +using MediaBrowser.Controller.Dlna; using MediaBrowser.Controller.Drawing; using MediaBrowser.Controller.Dto; using MediaBrowser.Controller.Library; @@ -58,7 +59,7 @@ namespace MediaBrowser.Api.Playback.Progressive /// public class VideoService : BaseProgressiveStreamingService { - public VideoService(IServerConfigurationManager serverConfig, IUserManager userManager, ILibraryManager libraryManager, IIsoManager isoManager, IMediaEncoder mediaEncoder, IDtoService dtoService, IFileSystem fileSystem, IItemRepository itemRepository, ILiveTvManager liveTvManager, IEncodingManager encodingManager, IHttpClient httpClient, IImageProcessor imageProcessor) : base(serverConfig, userManager, libraryManager, isoManager, mediaEncoder, dtoService, fileSystem, itemRepository, liveTvManager, encodingManager, httpClient, imageProcessor) + public VideoService(IServerConfigurationManager serverConfig, IUserManager userManager, ILibraryManager libraryManager, IIsoManager isoManager, IMediaEncoder mediaEncoder, IDtoService dtoService, IFileSystem fileSystem, IItemRepository itemRepository, ILiveTvManager liveTvManager, IEncodingManager encodingManager, IDlnaManager dlnaManager, IHttpClient httpClient, IImageProcessor imageProcessor) : base(serverConfig, userManager, libraryManager, isoManager, mediaEncoder, dtoService, fileSystem, itemRepository, liveTvManager, encodingManager, dlnaManager, httpClient, imageProcessor) { } diff --git a/MediaBrowser.Api/Playback/StreamState.cs b/MediaBrowser.Api/Playback/StreamState.cs index ecc5c93ef2..504d7d921b 100644 --- a/MediaBrowser.Api/Playback/StreamState.cs +++ b/MediaBrowser.Api/Playback/StreamState.cs @@ -1,4 +1,5 @@ using MediaBrowser.Common.Net; +using MediaBrowser.Controller.Dlna; using MediaBrowser.Model.Entities; using MediaBrowser.Model.IO; using System.Collections.Generic; @@ -77,8 +78,21 @@ namespace MediaBrowser.Api.Playback public string InputAudioCodec { get; set; } + public string MimeType { get; set; } + public string OrgPn { get; set; } + + // DLNA Settings + public bool EstimateContentLength { get; set; } + public bool EnableMpegtsM2TsMode { get; set; } + public TranscodeSeekInfo TranscodeSeekInfo { get; set; } + public string GetMimeType(string outputPath) { + if (!string.IsNullOrEmpty(MimeType)) + { + return MimeType; + } + return MimeTypes.GetMimeType(outputPath); } } diff --git a/MediaBrowser.Controller/Dlna/DeviceIdentification.cs b/MediaBrowser.Controller/Dlna/DeviceIdentification.cs index 461c77537c..7b8e3a1e72 100644 --- a/MediaBrowser.Controller/Dlna/DeviceIdentification.cs +++ b/MediaBrowser.Controller/Dlna/DeviceIdentification.cs @@ -41,9 +41,7 @@ namespace MediaBrowser.Controller.Dlna /// /// Gets or sets the manufacturer. /// - /// - /// The manufacturer. - /// + /// The manufacturer. public string Manufacturer { get; set; } /// /// Gets or sets the manufacturer URL. diff --git a/MediaBrowser.Controller/Dlna/DeviceProfile.cs b/MediaBrowser.Controller/Dlna/DeviceProfile.cs index f3de1bc34a..f34c4bf645 100644 --- a/MediaBrowser.Controller/Dlna/DeviceProfile.cs +++ b/MediaBrowser.Controller/Dlna/DeviceProfile.cs @@ -1,4 +1,7 @@ - +using MediaBrowser.Model.Entities; +using System; +using System.Linq; + namespace MediaBrowser.Controller.Dlna { public class DeviceProfile @@ -9,12 +12,6 @@ namespace MediaBrowser.Controller.Dlna /// The name. public string Name { get; set; } - /// - /// Gets or sets the type of the client. - /// - /// The type of the client. - public string ClientType { get; set; } - /// /// Gets or sets the transcoding profiles. /// @@ -76,5 +73,141 @@ namespace MediaBrowser.Controller.Dlna CodecProfiles = new CodecProfile[] { }; ContainerProfiles = new ContainerProfile[] { }; } + + public TranscodingProfile GetAudioTranscodingProfile(string container, string audioCodec) + { + container = (container ?? string.Empty).TrimStart('.'); + + return TranscodingProfiles.FirstOrDefault(i => + { + if (i.Type != DlnaProfileType.Audio) + { + return false; + } + + if (!string.Equals(container, i.Container, StringComparison.OrdinalIgnoreCase)) + { + return false; + } + + if (!i.GetAudioCodecs().Contains(audioCodec ?? string.Empty)) + { + return false; + } + + return true; + }); + } + + public TranscodingProfile GetVideoTranscodingProfile(string container, string audioCodec, string videoCodec) + { + container = (container ?? string.Empty).TrimStart('.'); + + return TranscodingProfiles.FirstOrDefault(i => + { + if (i.Type != DlnaProfileType.Video) + { + return false; + } + + if (!string.Equals(container, i.Container, StringComparison.OrdinalIgnoreCase)) + { + return false; + } + + if (!i.GetAudioCodecs().Contains(audioCodec ?? string.Empty)) + { + return false; + } + + if (!string.Equals(videoCodec, i.VideoCodec, StringComparison.OrdinalIgnoreCase)) + { + return false; + } + + return true; + }); + } + + public MediaProfile GetAudioMediaProfile(string container, string audioCodec, MediaStream audioStream) + { + container = (container ?? string.Empty).TrimStart('.'); + + return MediaProfiles.FirstOrDefault(i => + { + if (i.Type != DlnaProfileType.Audio) + { + return false; + } + + var containers = i.GetContainers().ToList(); + if (containers.Count > 0 && !containers.Contains(container)) + { + return false; + } + + var audioCodecs = i.GetAudioCodecs().ToList(); + if (audioCodecs.Count > 0 && !audioCodecs.Contains(audioCodec ?? string.Empty)) + { + return false; + } + + return true; + }); + } + + public MediaProfile GetVideoMediaProfile(string container, string audioCodec, string videoCodec, MediaStream audioStream, MediaStream videoStream) + { + container = (container ?? string.Empty).TrimStart('.'); + + return MediaProfiles.FirstOrDefault(i => + { + if (i.Type != DlnaProfileType.Video) + { + return false; + } + + var containers = i.GetContainers().ToList(); + if (containers.Count > 0 && !containers.Contains(container)) + { + return false; + } + + var audioCodecs = i.GetAudioCodecs().ToList(); + if (audioCodecs.Count > 0 && !audioCodecs.Contains(audioCodec ?? string.Empty)) + { + return false; + } + + var videoCodecs = i.GetVideoCodecs().ToList(); + if (videoCodecs.Count > 0 && !videoCodecs.Contains(videoCodec ?? string.Empty)) + { + return false; + } + + return true; + }); + } + + public MediaProfile GetPhotoMediaProfile(string container) + { + container = (container ?? string.Empty).TrimStart('.'); + + return MediaProfiles.FirstOrDefault(i => + { + if (i.Type != DlnaProfileType.Photo) + { + return false; + } + + var containers = i.GetContainers().ToList(); + if (containers.Count > 0 && !containers.Contains(container)) + { + return false; + } + + return true; + }); + } } } diff --git a/MediaBrowser.Controller/Dlna/IDlnaManager.cs b/MediaBrowser.Controller/Dlna/IDlnaManager.cs index 6de17e5511..22d13fc3ad 100644 --- a/MediaBrowser.Controller/Dlna/IDlnaManager.cs +++ b/MediaBrowser.Controller/Dlna/IDlnaManager.cs @@ -16,6 +16,13 @@ namespace MediaBrowser.Controller.Dlna /// DlnaProfile. DeviceProfile GetDefaultProfile(); + /// + /// Gets the profile. + /// + /// The headers. + /// DeviceProfile. + DeviceProfile GetProfile(IDictionary headers); + /// /// Gets the profile. /// diff --git a/MediaBrowser.Controller/Dlna/MediaProfile.cs b/MediaBrowser.Controller/Dlna/MediaProfile.cs index 1d2613face..9a9b56ddd5 100644 --- a/MediaBrowser.Controller/Dlna/MediaProfile.cs +++ b/MediaBrowser.Controller/Dlna/MediaProfile.cs @@ -19,6 +19,11 @@ namespace MediaBrowser.Controller.Dlna { Conditions = new ProfileCondition[] {}; } + + public List GetContainers() + { + return (Container ?? string.Empty).Split(',').Where(i => !string.IsNullOrWhiteSpace(i)).ToList(); + } public List GetAudioCodecs() { diff --git a/MediaBrowser.Controller/Dlna/TranscodingProfile.cs b/MediaBrowser.Controller/Dlna/TranscodingProfile.cs index 007cb632e4..d4cfae9893 100644 --- a/MediaBrowser.Controller/Dlna/TranscodingProfile.cs +++ b/MediaBrowser.Controller/Dlna/TranscodingProfile.cs @@ -1,4 +1,6 @@ - +using System.Collections.Generic; +using System.Linq; + namespace MediaBrowser.Controller.Dlna { public class TranscodingProfile @@ -11,7 +13,7 @@ namespace MediaBrowser.Controller.Dlna public string AudioCodec { get; set; } public bool EstimateContentLength { get; set; } - + public bool EnableMpegtsM2TsMode { get; set; } public TranscodeSeekInfo TranscodeSeekInfo { get; set; } public TranscodingSetting[] Settings { get; set; } @@ -21,7 +23,11 @@ namespace MediaBrowser.Controller.Dlna Settings = new TranscodingSetting[] { }; } - public bool EnableMpegtsM2TsMode { get; set; } + + public List GetAudioCodecs() + { + return (AudioCodec ?? string.Empty).Split(',').Where(i => !string.IsNullOrWhiteSpace(i)).ToList(); + } } public class TranscodingSetting diff --git a/MediaBrowser.Controller/Providers/BaseItemXmlParser.cs b/MediaBrowser.Controller/Providers/BaseItemXmlParser.cs index d71c7af323..70b49efece 100644 --- a/MediaBrowser.Controller/Providers/BaseItemXmlParser.cs +++ b/MediaBrowser.Controller/Providers/BaseItemXmlParser.cs @@ -1,5 +1,4 @@ using MediaBrowser.Controller.Entities; -using MediaBrowser.Controller.Entities.Audio; using MediaBrowser.Controller.Persistence; using MediaBrowser.Model.Entities; using MediaBrowser.Model.Logging; @@ -284,22 +283,6 @@ namespace MediaBrowser.Controller.Providers break; } - case "TagLine": - { - var tagline = reader.ReadElementContentAsString(); - - var hasTaglines = item as IHasTaglines; - if (hasTaglines != null) - { - if (!string.IsNullOrWhiteSpace(tagline)) - { - hasTaglines.AddTagline(tagline); - } - } - - break; - } - case "Language": { var val = reader.ReadElementContentAsString(); @@ -380,9 +363,7 @@ namespace MediaBrowser.Controller.Providers } case "ContentRating": - case "certification": case "MPAARating": - case "ESRBRating": { var rating = reader.ReadElementContentAsString(); @@ -415,7 +396,6 @@ namespace MediaBrowser.Controller.Providers break; } - case "Runtime": case "RunningTime": { var text = reader.ReadElementContentAsString(); @@ -431,19 +411,6 @@ namespace MediaBrowser.Controller.Providers break; } - case "Genre": - { - foreach (var name in SplitNames(reader.ReadElementContentAsString())) - { - if (string.IsNullOrWhiteSpace(name)) - { - continue; - } - item.AddGenre(name); - } - break; - } - case "AspectRatio": { var val = reader.ReadElementContentAsString(); @@ -587,7 +554,6 @@ namespace MediaBrowser.Controller.Providers break; } - case "ReleaseYear": case "ProductionYear": { var val = reader.ReadElementContentAsString(); @@ -606,7 +572,6 @@ namespace MediaBrowser.Controller.Providers case "Rating": case "IMDBrating": - case "TGDBRating": { var rating = reader.ReadElementContentAsString(); @@ -683,22 +648,6 @@ namespace MediaBrowser.Controller.Providers } break; } - case "MusicbrainzId": - { - var mbz = reader.ReadElementContentAsString(); - if (!string.IsNullOrWhiteSpace(mbz)) - { - if (item is MusicAlbum) - { - item.SetProviderId(MetadataProviders.MusicBrainzAlbum, mbz); - } - else if (item is MusicArtist) - { - item.SetProviderId(MetadataProviders.MusicBrainzArtist, mbz); - } - } - break; - } case "MusicBrainzAlbumId": { var mbz = reader.ReadElementContentAsString(); @@ -802,9 +751,7 @@ namespace MediaBrowser.Controller.Providers } break; - case "IMDB_ID": case "IMDB": - case "IMDbId": var imDbId = reader.ReadElementContentAsString(); if (!string.IsNullOrWhiteSpace(imDbId)) { @@ -856,15 +803,6 @@ namespace MediaBrowser.Controller.Providers break; } - case "ParentalRating": - { - using (var subtree = reader.ReadSubtree()) - { - FetchFromParentalRatingNode(subtree, item); - } - break; - } - case "Studios": { using (var subtree = reader.ReadSubtree()) @@ -1227,32 +1165,6 @@ namespace MediaBrowser.Controller.Providers } } - /// - /// Fetches from parental rating node. - /// - /// The reader. - /// The item. - private void FetchFromParentalRatingNode(XmlReader reader, T item) - { - reader.MoveToContent(); - - while (reader.Read()) - { - if (reader.NodeType == XmlNodeType.Element) - { - switch (reader.Name) - { - // Removed support for "Value" tag as it conflicted with MPAA rating but leaving this function for possible - // future support of "Description" -ebr - - default: - reader.Skip(); - break; - } - } - } - } - /// /// Gets the persons from XML node. /// diff --git a/MediaBrowser.Dlna/DlnaManager.cs b/MediaBrowser.Dlna/DlnaManager.cs index c6da865cd7..78876d239c 100644 --- a/MediaBrowser.Dlna/DlnaManager.cs +++ b/MediaBrowser.Dlna/DlnaManager.cs @@ -3,6 +3,7 @@ using MediaBrowser.Common.IO; using MediaBrowser.Controller.Dlna; using MediaBrowser.Dlna.Profiles; using MediaBrowser.Model.Serialization; +using System; using System.Collections.Generic; using System.Linq; using System.Text.RegularExpressions; @@ -43,7 +44,8 @@ namespace MediaBrowser.Dlna new WdtvLiveProfile(), new DenonAvrProfile(), new LinksysDMA2100Profile(), - new LgTvProfile() + new LgTvProfile(), + new Foobar2000Profile() }; foreach (var item in list) @@ -124,5 +126,38 @@ namespace MediaBrowser.Dlna return true; } + + public DeviceProfile GetProfile(IDictionary headers) + { + return GetProfiles().FirstOrDefault(i => IsMatch(headers, i.Identification)) ?? + GetDefaultProfile(); + } + + private bool IsMatch(IDictionary headers, DeviceIdentification profileInfo) + { + return profileInfo.Headers.Any(i => IsMatch(headers, i)); + } + + private bool IsMatch(IDictionary headers, HttpHeaderInfo header) + { + string value; + + if (headers.TryGetValue(header.Name, out value)) + { + switch (header.Match) + { + case HeaderMatchType.Equals: + return string.Equals(value, header.Value, StringComparison.OrdinalIgnoreCase); + case HeaderMatchType.Substring: + return value.IndexOf(header.Value, StringComparison.OrdinalIgnoreCase) != -1; + case HeaderMatchType.Regex: + return Regex.IsMatch(value, header.Value, RegexOptions.IgnoreCase); + default: + throw new ArgumentException("Unrecognized HeaderMatchType"); + } + } + + return false; + } } } \ No newline at end of file diff --git a/MediaBrowser.Dlna/MediaBrowser.Dlna.csproj b/MediaBrowser.Dlna/MediaBrowser.Dlna.csproj index bea281b614..bdfcae39b6 100644 --- a/MediaBrowser.Dlna/MediaBrowser.Dlna.csproj +++ b/MediaBrowser.Dlna/MediaBrowser.Dlna.csproj @@ -61,7 +61,6 @@ - Code @@ -70,7 +69,8 @@ - + + @@ -100,7 +100,6 @@ - diff --git a/MediaBrowser.Dlna/PlayTo/Device.cs b/MediaBrowser.Dlna/PlayTo/Device.cs index 2b43c019c0..a677cf5dd7 100644 --- a/MediaBrowser.Dlna/PlayTo/Device.cs +++ b/MediaBrowser.Dlna/PlayTo/Device.cs @@ -607,7 +607,7 @@ namespace MediaBrowser.Dlna.PlayTo url = "/" + url; var httpClient = new SsdpHttpClient(_httpClient, _config); - var document = await httpClient.GetDataAsync(new Uri(Properties.BaseUrl + url)); + var document = await httpClient.GetDataAsync(Properties.BaseUrl + url); AvCommands = TransportCommands.Create(document); } @@ -625,7 +625,7 @@ namespace MediaBrowser.Dlna.PlayTo url = "/" + url; var httpClient = new SsdpHttpClient(_httpClient, _config); - var document = await httpClient.GetDataAsync(new Uri(Properties.BaseUrl + url)); + var document = await httpClient.GetDataAsync(Properties.BaseUrl + url); RendererCommands = TransportCommands.Create(document); } @@ -646,7 +646,7 @@ namespace MediaBrowser.Dlna.PlayTo { var ssdpHttpClient = new SsdpHttpClient(httpClient, config); - var document = await ssdpHttpClient.GetDataAsync(url).ConfigureAwait(false); + var document = await ssdpHttpClient.GetDataAsync(url.ToString()).ConfigureAwait(false); var deviceProperties = new DeviceInfo(); @@ -681,10 +681,18 @@ namespace MediaBrowser.Dlna.PlayTo var presentationUrl = document.Descendants(uPnpNamespaces.ud.GetName("presentationURL")).FirstOrDefault(); if (presentationUrl != null) deviceProperties.PresentationUrl = presentationUrl.Value; + var modelUrl = document.Descendants(uPnpNamespaces.ud.GetName("modelURL")).FirstOrDefault(); if (modelUrl != null) deviceProperties.ModelUrl = modelUrl.Value; - + + var serialNumber = document.Descendants(uPnpNamespaces.ud.GetName("serialNumber")).FirstOrDefault(); + if (serialNumber != null) + deviceProperties.SerialNumber = serialNumber.Value; + + var modelDescription = document.Descendants(uPnpNamespaces.ud.GetName("modelDescription")).FirstOrDefault(); + if (modelDescription != null) + deviceProperties.ModelDescription = modelDescription.Value; deviceProperties.BaseUrl = String.Format("http://{0}:{1}", url.Host, url.Port); @@ -724,7 +732,6 @@ namespace MediaBrowser.Dlna.PlayTo if (isRenderer) { - var device = new Device(deviceProperties, httpClient, logger, config); await device.GetRenderingProtocolAsync().ConfigureAwait(false); diff --git a/MediaBrowser.Dlna/PlayTo/DeviceInfo.cs b/MediaBrowser.Dlna/PlayTo/DeviceInfo.cs index c57e95c194..122549c7d3 100644 --- a/MediaBrowser.Dlna/PlayTo/DeviceInfo.cs +++ b/MediaBrowser.Dlna/PlayTo/DeviceInfo.cs @@ -1,5 +1,5 @@ -using System.Collections.Generic; -using MediaBrowser.Controller.Dlna; +using MediaBrowser.Controller.Dlna; +using System.Collections.Generic; namespace MediaBrowser.Dlna.PlayTo { @@ -17,27 +17,18 @@ namespace MediaBrowser.Dlna.PlayTo public string ClientType { get; set; } - private string _displayName = string.Empty; - public string DisplayName - { - get - { - return string.IsNullOrEmpty(_displayName) ? Name : _displayName; - } - set - { - _displayName = value; - } - } - public string ModelName { get; set; } public string ModelNumber { get; set; } + public string ModelDescription { get; set; } + public string ModelUrl { get; set; } public string Manufacturer { get; set; } + public string SerialNumber { get; set; } + public string ManufacturerUrl { get; set; } public string PresentationUrl { get; set; } @@ -75,7 +66,9 @@ namespace MediaBrowser.Dlna.PlayTo ModelNumber = ModelNumber, FriendlyName = Name, ManufacturerUrl = ManufacturerUrl, - ModelUrl = ModelUrl + ModelUrl = ModelUrl, + ModelDescription = ModelDescription, + SerialNumber = SerialNumber }; } } diff --git a/MediaBrowser.Dlna/PlayTo/DidlBuilder.cs b/MediaBrowser.Dlna/PlayTo/DidlBuilder.cs index 04f9a4644c..1327da1480 100644 --- a/MediaBrowser.Dlna/PlayTo/DidlBuilder.cs +++ b/MediaBrowser.Dlna/PlayTo/DidlBuilder.cs @@ -9,31 +9,27 @@ namespace MediaBrowser.Dlna.PlayTo { internal class DidlBuilder { - #region Constants + const string CRLF = "\r\n"; + const string UNKNOWN = "Unknown"; - internal const string CRLF = "\r\n"; - internal const string UNKNOWN = "Unknown"; - - internal const string DIDL_START = @"" + CRLF; - internal const string DIDL_TITLE = @" {0}" + CRLF; - internal const string DIDL_ARTIST = @"{0}" + CRLF; - internal const string DIDL_ALBUM = @"{0}" + CRLF; - internal const string DIDL_TRACKNUM = @"0" + CRLF; - internal const string DIDL_VIDEOCLASS = @" object.item.videoItem" + CRLF; - internal const string DIDL_AUDIOCLASS = @" object.item.audioItem.musicTrack" + CRLF; - internal const string DIDL_IMAGE = @" {0}" + CRLF + - @" {0}" + CRLF; - internal const string DIDL_RELEASEDATE = @" {0}" + CRLF; - internal const string DIDL_GENRE = @" {0}" + CRLF; - internal const string DESCRIPTION = @" {0}" + CRLF; - internal const string DIDL_VIDEO_RES = @" {4}" + CRLF; - internal const string DIDL_AUDIO_RES = @" {3}" + CRLF; - internal const string DIDL_IMAGE_RES = @" {0}" + CRLF; - internal const string DIDL_ALBUMIMAGE_RES = @" {0}" + CRLF; - internal const string DIDL_RATING = @" {0}" + CRLF; - internal const string DIDL_END = ""; - - #endregion + const string DIDL_START = @"" + CRLF; + const string DIDL_TITLE = @" {0}" + CRLF; + const string DIDL_ARTIST = @"{0}" + CRLF; + const string DIDL_ALBUM = @"{0}" + CRLF; + const string DIDL_TRACKNUM = @"{0}" + CRLF; + const string DIDL_VIDEOCLASS = @" object.item.videoItem" + CRLF; + const string DIDL_AUDIOCLASS = @" object.item.audioItem.musicTrack" + CRLF; + const string DIDL_IMAGE = @" {0}" + CRLF + + @" {0}" + CRLF; + const string DIDL_RELEASEDATE = @" {0}" + CRLF; + const string DIDL_GENRE = @" {0}" + CRLF; + const string DESCRIPTION = @" {0}" + CRLF; + const string DIDL_VIDEO_RES = @" {4}" + CRLF; + const string DIDL_AUDIO_RES = @" {3}" + CRLF; + const string DIDL_IMAGE_RES = @" {0}" + CRLF; + const string DIDL_ALBUMIMAGE_RES = @" {0}" + CRLF; + const string DIDL_RATING = @" {0}" + CRLF; + const string DIDL_END = ""; /// /// Builds a Didl MetaData object for the specified dto. @@ -44,7 +40,7 @@ namespace MediaBrowser.Dlna.PlayTo /// The stream URL. /// The streams. /// System.String. - internal static string Build(BaseItem dto, string userId, string serverAddress, string streamUrl, IEnumerable streams) + public static string Build(BaseItem dto, string userId, string serverAddress, string streamUrl, IEnumerable streams) { string response = string.Format(DIDL_START, dto.Id, userId); response += string.Format(DIDL_TITLE, dto.Name.Replace("&", "and")); @@ -53,7 +49,12 @@ namespace MediaBrowser.Dlna.PlayTo else response += DIDL_AUDIOCLASS; - response += string.Format(DIDL_IMAGE, GetImageUrl(dto, serverAddress)); + var imageUrl = GetImageUrl(dto, serverAddress); + + if (!string.IsNullOrEmpty(imageUrl)) + { + response += string.Format(DIDL_IMAGE, imageUrl); + } response += string.Format(DIDL_RELEASEDATE, GetDateString(dto.PremiereDate)); //TODO Add genres to didl; @@ -63,7 +64,11 @@ namespace MediaBrowser.Dlna.PlayTo { response += string.Format(DESCRIPTION, UNKNOWN); response += GetVideoDIDL(dto, streamUrl, streams); - response += string.Format(DIDL_IMAGE_RES, GetImageUrl(dto, serverAddress)); + + if (!string.IsNullOrEmpty(imageUrl)) + { + response += string.Format(DIDL_IMAGE_RES, imageUrl); + } } else { @@ -74,25 +79,25 @@ namespace MediaBrowser.Dlna.PlayTo response += string.Format(DIDL_ARTIST, audio.Artists.FirstOrDefault() ?? UNKNOWN); response += string.Format(DIDL_ALBUM, audio.Album); - // TODO: Bad format string? response += string.Format(DIDL_TRACKNUM, audio.IndexNumber ?? 0); } response += GetAudioDIDL(dto, streamUrl, streams); - response += string.Format(DIDL_ALBUMIMAGE_RES, GetImageUrl(dto, serverAddress)); + + if (!string.IsNullOrEmpty(imageUrl)) + { + response += string.Format(DIDL_ALBUMIMAGE_RES, imageUrl); + } } response += DIDL_END; return response; - } - #region Private methods - private static string GetVideoDIDL(BaseItem dto, string streamUrl, IEnumerable streams) { - var videostream = streams.Where(stream => stream.Type == Model.Entities.MediaStreamType.Video).OrderBy(s => s.IsDefault).FirstOrDefault(); + var videostream = streams.Where(stream => stream.Type == MediaStreamType.Video).OrderBy(s => s.IsDefault ? 0 : 1).FirstOrDefault(); if (videostream == null) { @@ -105,7 +110,7 @@ namespace MediaBrowser.Dlna.PlayTo private static string GetAudioDIDL(BaseItem dto, string streamUrl, IEnumerable streams) { - var audiostream = streams.Where(stream => stream.Type == MediaStreamType.Audio).OrderBy(s => s.IsDefault).FirstOrDefault(); + var audiostream = streams.Where(stream => stream.Type == MediaStreamType.Audio).OrderBy(s => s.IsDefault ? 0 : 1).FirstOrDefault(); if (audiostream == null) { @@ -118,14 +123,14 @@ namespace MediaBrowser.Dlna.PlayTo private static string GetImageUrl(BaseItem dto, string serverAddress) { - var imageType = ImageType.Primary; + const ImageType imageType = ImageType.Primary; - if (!dto.HasImage(ImageType.Primary)) + if (!dto.HasImage(imageType)) { - dto = dto.Parents.FirstOrDefault(i => i.HasImage(ImageType.Primary)); + dto = dto.Parents.FirstOrDefault(i => i.HasImage(imageType)); } - return string.Format("{0}/Items/{1}/Images/{2}", serverAddress, dto.Id, imageType); + return dto == null ? null : string.Format("{0}/Items/{1}/Images/{2}", serverAddress, dto.Id, imageType); } private static string GetDurationString(BaseItem dto) @@ -148,7 +153,5 @@ namespace MediaBrowser.Dlna.PlayTo { return string.Equals(item.MediaType, MediaType.Video, StringComparison.OrdinalIgnoreCase); } - - #endregion } } diff --git a/MediaBrowser.Dlna/PlayTo/DlnaController.cs b/MediaBrowser.Dlna/PlayTo/DlnaController.cs index ecda07f0bc..0b0c03fcd4 100644 --- a/MediaBrowser.Dlna/PlayTo/DlnaController.cs +++ b/MediaBrowser.Dlna/PlayTo/DlnaController.cs @@ -140,8 +140,15 @@ namespace MediaBrowser.Dlna.PlayTo { _updateTimer.Change(Timeout.Infinite, Timeout.Infinite); - //Session is inactive, mark it for Disposal and don't start the elapsed timer. - await _sessionManager.ReportSessionEnded(_session.Id); + try + { + // Session is inactive, mark it for Disposal and don't start the elapsed timer. + await _sessionManager.ReportSessionEnded(_session.Id); + } + catch (Exception ex) + { + _logger.ErrorException("Error in ReportSessionEnded", ex); + } } } @@ -156,7 +163,15 @@ namespace MediaBrowser.Dlna.PlayTo if (!_playbackStarted) { - await _sessionManager.OnPlaybackStart(new PlaybackInfo { Item = _currentItem, SessionId = _session.Id, CanSeek = true, QueueableMediaTypes = new List { "Audio", "Video" } }).ConfigureAwait(false); + await _sessionManager.OnPlaybackStart(new PlaybackInfo + { + Item = _currentItem, + SessionId = _session.Id, + CanSeek = true, + QueueableMediaTypes = new List { "Audio", "Video" } + + }).ConfigureAwait(false); + _playbackStarted = true; } @@ -403,7 +418,6 @@ namespace MediaBrowser.Dlna.PlayTo var playlistItem = GetPlaylistItem(item, streams, profile); playlistItem.StartPositionTicks = startPostionTicks; - playlistItem.DeviceProfileName = profile.Name; if (playlistItem.MediaType == DlnaProfileType.Audio) { @@ -414,8 +428,7 @@ namespace MediaBrowser.Dlna.PlayTo playlistItem.StreamUrl = StreamHelper.GetVideoUrl(_device.Properties, playlistItem, streams, serverAddress); } - var didl = DidlBuilder.Build(item, _session.UserId.ToString(), serverAddress, playlistItem.StreamUrl, streams); - playlistItem.Didl = didl; + playlistItem.Didl = DidlBuilder.Build(item, _session.UserId.ToString(), serverAddress, playlistItem.StreamUrl, streams); return playlistItem; } diff --git a/MediaBrowser.Dlna/PlayTo/DlnaControllerFactory.cs b/MediaBrowser.Dlna/PlayTo/DlnaControllerFactory.cs deleted file mode 100644 index 720dc200b4..0000000000 --- a/MediaBrowser.Dlna/PlayTo/DlnaControllerFactory.cs +++ /dev/null @@ -1,31 +0,0 @@ -using MediaBrowser.Common.Net; -using MediaBrowser.Controller.Library; -using MediaBrowser.Controller.Persistence; -using MediaBrowser.Controller.Session; -using MediaBrowser.Model.Logging; - -namespace MediaBrowser.Dlna.PlayTo -{ - public class PlayToControllerFactory : ISessionControllerFactory - { - private readonly ISessionManager _sessionManager; - private readonly IItemRepository _itemRepository; - private readonly ILibraryManager _libraryManager; - private readonly ILogger _logger; - private readonly INetworkManager _networkManager; - - public PlayToControllerFactory(ISessionManager sessionManager, IItemRepository itemRepository, ILibraryManager libraryManager, ILogManager logManager, INetworkManager networkManager) - { - _itemRepository = itemRepository; - _sessionManager = sessionManager; - _libraryManager = libraryManager; - _networkManager = networkManager; - _logger = logManager.GetLogger("PlayTo"); - } - - public ISessionController GetSessionController(SessionInfo session) - { - return null; - } - } -} diff --git a/MediaBrowser.Dlna/PlayTo/PlayToManager.cs b/MediaBrowser.Dlna/PlayTo/PlayToManager.cs index ca76116feb..297f7a696b 100644 --- a/MediaBrowser.Dlna/PlayTo/PlayToManager.cs +++ b/MediaBrowser.Dlna/PlayTo/PlayToManager.cs @@ -5,16 +5,17 @@ using MediaBrowser.Controller.Dlna; using MediaBrowser.Controller.Library; using MediaBrowser.Controller.Persistence; using MediaBrowser.Controller.Session; +using MediaBrowser.Dlna.Ssdp; using MediaBrowser.Model.Entities; using MediaBrowser.Model.Logging; using MediaBrowser.Model.Session; using System; using System.Collections.Concurrent; +using System.Collections.Generic; using System.Linq; using System.Net; using System.Net.NetworkInformation; using System.Net.Sockets; -using System.Text; using System.Threading; using System.Threading.Tasks; @@ -126,10 +127,9 @@ namespace MediaBrowser.Dlna.PlayTo if (receivedBytes > 0) { - var rawData = Encoding.UTF8.GetString(receiveBuffer, 0, receivedBytes); - var uri = SsdpHelper.ParseSsdpResponse(rawData); + var headers = SsdpHelper.ParseSsdpResponse(receiveBuffer); - TryCreateController(uri); + TryCreateController(headers); } } @@ -146,13 +146,20 @@ namespace MediaBrowser.Dlna.PlayTo }, _tokenSource.Token, TaskCreationOptions.LongRunning); } - private void TryCreateController(Uri uri) + private void TryCreateController(IDictionary headers) { + string location; + + if (!headers.TryGetValue("Location", out location)) + { + return; + } + Task.Run(async () => { try { - await CreateController(uri).ConfigureAwait(false); + await CreateController(new Uri(location)).ConfigureAwait(false); } catch (OperationCanceledException) { @@ -221,46 +228,25 @@ namespace MediaBrowser.Dlna.PlayTo if (device != null && device.RendererCommands != null && !_sessionManager.Sessions.Any(s => string.Equals(s.DeviceId, device.Properties.UUID) && s.IsActive)) { - GetProfileSettings(device.Properties); - - var sessionInfo = await _sessionManager.LogSessionActivity(device.Properties.ClientType, device.Properties.Name, device.Properties.UUID, device.Properties.DisplayName, uri.OriginalString, null) + var sessionInfo = await _sessionManager.LogSessionActivity(device.Properties.ClientType, _appHost.ApplicationVersion.ToString(), device.Properties.UUID, device.Properties.Name, uri.OriginalString, null) .ConfigureAwait(false); - _sessionManager.ReportCapabilities(sessionInfo.Id, new SessionCapabilities - { - PlayableMediaTypes = new[] { MediaType.Audio, MediaType.Video, MediaType.Photo }, - SupportsFullscreenToggle = false - }); - var controller = sessionInfo.SessionController as PlayToController; if (controller == null) { sessionInfo.SessionController = controller = new PlayToController(sessionInfo, _sessionManager, _itemRepository, _libraryManager, _logger, _networkManager, _dlnaManager, _userManager, _appHost); + + controller.Init(device); + + _sessionManager.ReportCapabilities(sessionInfo.Id, new SessionCapabilities + { + PlayableMediaTypes = new[] { MediaType.Audio, MediaType.Video, MediaType.Photo }, + SupportsFullscreenToggle = false + }); + + _logger.Info("DLNA Session created for {0} - {1}", device.Properties.Name, device.Properties.ModelName); } - - controller.Init(device); - - _logger.Info("DLNA Session created for {0} - {1}", device.Properties.Name, device.Properties.ModelName); - } - } - - /// - /// Gets the profile settings. - /// - /// The device properties. - /// The TranscodeSettings for the device - private void GetProfileSettings(DeviceInfo deviceProperties) - { - var profile = _dlnaManager.GetProfile(deviceProperties.ToDeviceIdentification()); - - if (!string.IsNullOrWhiteSpace(profile.Name)) - { - deviceProperties.DisplayName = profile.Name; - } - if (!string.IsNullOrWhiteSpace(profile.ClientType)) - { - deviceProperties.ClientType = profile.ClientType; } } diff --git a/MediaBrowser.Dlna/PlayTo/PlaylistItem.cs b/MediaBrowser.Dlna/PlayTo/PlaylistItem.cs index 20f31cf9da..e1eea08240 100644 --- a/MediaBrowser.Dlna/PlayTo/PlaylistItem.cs +++ b/MediaBrowser.Dlna/PlayTo/PlaylistItem.cs @@ -33,8 +33,6 @@ namespace MediaBrowser.Dlna.PlayTo public int? SubtitleStreamIndex { get; set; } - public string DeviceProfileName { get; set; } - public int? MaxAudioChannels { get; set; } public int? AudioBitrate { get; set; } diff --git a/MediaBrowser.Dlna/PlayTo/PlaylistItemFactory.cs b/MediaBrowser.Dlna/PlayTo/PlaylistItemFactory.cs index 1b2d791136..0dec9bbf3f 100644 --- a/MediaBrowser.Dlna/PlayTo/PlaylistItemFactory.cs +++ b/MediaBrowser.Dlna/PlayTo/PlaylistItemFactory.cs @@ -162,7 +162,8 @@ namespace MediaBrowser.Dlna.PlayTo private void ApplyTranscodingConditions(PlaylistItem item, IEnumerable conditions) { - foreach (var condition in conditions.Where(i => !string.IsNullOrEmpty(i.Value))) + foreach (var condition in conditions + .Where(i => !string.IsNullOrEmpty(i.Value))) { var value = condition.Value; @@ -170,7 +171,7 @@ namespace MediaBrowser.Dlna.PlayTo { case ProfileConditionValue.AudioBitrate: { - var num = 0; + int num; if (int.TryParse(value, NumberStyles.Any, _usCulture, out num)) { item.AudioBitrate = num; @@ -179,7 +180,7 @@ namespace MediaBrowser.Dlna.PlayTo } case ProfileConditionValue.AudioChannels: { - var num = 0; + int num; if (int.TryParse(value, NumberStyles.Any, _usCulture, out num)) { item.MaxAudioChannels = num; @@ -199,7 +200,7 @@ namespace MediaBrowser.Dlna.PlayTo } case ProfileConditionValue.Height: { - var num = 0; + int num; if (int.TryParse(value, NumberStyles.Any, _usCulture, out num)) { item.MaxHeight = num; @@ -208,7 +209,7 @@ namespace MediaBrowser.Dlna.PlayTo } case ProfileConditionValue.VideoBitrate: { - var num = 0; + int num; if (int.TryParse(value, NumberStyles.Any, _usCulture, out num)) { item.VideoBitrate = num; @@ -217,7 +218,7 @@ namespace MediaBrowser.Dlna.PlayTo } case ProfileConditionValue.VideoFramerate: { - var num = 0; + int num; if (int.TryParse(value, NumberStyles.Any, _usCulture, out num)) { item.MaxFramerate = num; @@ -226,7 +227,7 @@ namespace MediaBrowser.Dlna.PlayTo } case ProfileConditionValue.VideoLevel: { - var num = 0; + int num; if (int.TryParse(value, NumberStyles.Any, _usCulture, out num)) { item.VideoLevel = num; @@ -235,7 +236,7 @@ namespace MediaBrowser.Dlna.PlayTo } case ProfileConditionValue.Width: { - var num = 0; + int num; if (int.TryParse(value, NumberStyles.Any, _usCulture, out num)) { item.MaxWidth = num; diff --git a/MediaBrowser.Dlna/PlayTo/SsdpHttpClient.cs b/MediaBrowser.Dlna/PlayTo/SsdpHttpClient.cs index f540a80041..b1ae21a437 100644 --- a/MediaBrowser.Dlna/PlayTo/SsdpHttpClient.cs +++ b/MediaBrowser.Dlna/PlayTo/SsdpHttpClient.cs @@ -2,7 +2,6 @@ using MediaBrowser.Controller.Configuration; using System; using System.IO; -using System.Net; using System.Text; using System.Threading.Tasks; using System.Xml.Linq; @@ -14,8 +13,6 @@ namespace MediaBrowser.Dlna.PlayTo private const string USERAGENT = "Microsoft-Windows/6.2 UPnP/1.0 Microsoft-DLNA DLNADOC/1.50"; private const string FriendlyName = "MediaBrowser"; - private static readonly CookieContainer Container = new CookieContainer(); - private readonly IHttpClient _httpClient; private readonly IServerConfigurationManager _config; @@ -31,7 +28,7 @@ namespace MediaBrowser.Dlna.PlayTo if (!serviceUrl.StartsWith("/")) serviceUrl = "/" + serviceUrl; - var response = await PostSoapDataAsync(new Uri(baseUrl + serviceUrl), "\"" + service.ServiceType + "#" + command + "\"", postData, header) + var response = await PostSoapDataAsync(baseUrl + serviceUrl, "\"" + service.ServiceType + "#" + command + "\"", postData, header) .ConfigureAwait(false); using (var stream = response.Content) @@ -43,11 +40,11 @@ namespace MediaBrowser.Dlna.PlayTo } } - public async Task SubscribeAsync(Uri url, string ip, int port, string localIp, int eventport, int timeOut = 3600) + public async Task SubscribeAsync(string url, string ip, int port, string localIp, int eventport, int timeOut = 3600) { var options = new HttpRequestOptions { - Url = url.ToString(), + Url = url, UserAgent = USERAGENT, LogRequest = _config.Configuration.DlnaOptions.EnableDebugLogging }; @@ -56,7 +53,6 @@ namespace MediaBrowser.Dlna.PlayTo options.RequestHeaders["CALLBACK"] = "<" + localIp + ":" + eventport + ">"; options.RequestHeaders["NT"] = "upnp:event"; options.RequestHeaders["TIMEOUT"] = "Second - " + timeOut; - //request.CookieContainer = Container; using (await _httpClient.Get(options).ConfigureAwait(false)) { @@ -75,24 +71,22 @@ namespace MediaBrowser.Dlna.PlayTo options.RequestHeaders["CALLBACK"] = "<" + localIp + ":" + eventport + ">"; options.RequestHeaders["NT"] = "upnp:event"; options.RequestHeaders["TIMEOUT"] = "Second - 3600"; - //request.CookieContainer = Container; using (await _httpClient.Get(options).ConfigureAwait(false)) { } } - public async Task GetDataAsync(Uri url) + public async Task GetDataAsync(string url) { var options = new HttpRequestOptions { - Url = url.ToString(), + Url = url, UserAgent = USERAGENT, LogRequest = _config.Configuration.DlnaOptions.EnableDebugLogging }; options.RequestHeaders["FriendlyName.DLNA.ORG"] = FriendlyName; - //request.CookieContainer = Container; using (var stream = await _httpClient.Get(options).ConfigureAwait(false)) { @@ -103,14 +97,14 @@ namespace MediaBrowser.Dlna.PlayTo } } - private Task PostSoapDataAsync(Uri url, string soapAction, string postData, string header = null, int timeOut = 20000) + private Task PostSoapDataAsync(string url, string soapAction, string postData, string header = null) { if (!soapAction.StartsWith("\"")) soapAction = "\"" + soapAction + "\""; var options = new HttpRequestOptions { - Url = url.ToString(), + Url = url, UserAgent = USERAGENT, LogRequest = _config.Configuration.DlnaOptions.EnableDebugLogging }; diff --git a/MediaBrowser.Dlna/PlayTo/StreamHelper.cs b/MediaBrowser.Dlna/PlayTo/StreamHelper.cs index 61c3bdd730..a4855c94f2 100644 --- a/MediaBrowser.Dlna/PlayTo/StreamHelper.cs +++ b/MediaBrowser.Dlna/PlayTo/StreamHelper.cs @@ -43,15 +43,10 @@ namespace MediaBrowser.Dlna.PlayTo /// private static string BuildDlnaUrl(DeviceInfo deviceProperties, PlaylistItem item) { - var profile = item.TranscodingSettings.Where(i => i.Name == TranscodingSettingType.VideoProfile) - .Select(i => i.Value) - .FirstOrDefault(); - var usCulture = new CultureInfo("en-US"); var list = new List { - item.DeviceProfileName ?? string.Empty, deviceProperties.UUID ?? string.Empty, item.MediaSourceId ?? string.Empty, (!item.Transcode).ToString().ToLower(), @@ -66,7 +61,6 @@ namespace MediaBrowser.Dlna.PlayTo item.MaxWidth.HasValue ? item.MaxWidth.Value.ToString(usCulture) : string.Empty, item.MaxHeight.HasValue ? item.MaxHeight.Value.ToString(usCulture) : string.Empty, item.StartPositionTicks.ToString(usCulture), - profile ?? string.Empty, item.VideoLevel.HasValue ? item.VideoLevel.Value.ToString(usCulture) : string.Empty }; diff --git a/MediaBrowser.Dlna/Profiles/DefaultProfile.cs b/MediaBrowser.Dlna/Profiles/DefaultProfile.cs index 710f02df2e..214b6f814d 100644 --- a/MediaBrowser.Dlna/Profiles/DefaultProfile.cs +++ b/MediaBrowser.Dlna/Profiles/DefaultProfile.cs @@ -6,9 +6,10 @@ namespace MediaBrowser.Dlna.Profiles { public DefaultProfile() { + Name = "Generic Device"; + ProtocolInfo = "DLNA"; - ClientType = "DLNA"; Manufacturer = "Media Browser"; ModelDescription = "Media Browser"; ModelName = "Media Browser"; diff --git a/MediaBrowser.Dlna/Profiles/Foobar2000Profile.cs b/MediaBrowser.Dlna/Profiles/Foobar2000Profile.cs new file mode 100644 index 0000000000..877f1a6665 --- /dev/null +++ b/MediaBrowser.Dlna/Profiles/Foobar2000Profile.cs @@ -0,0 +1,27 @@ +using MediaBrowser.Controller.Dlna; + +namespace MediaBrowser.Dlna.Profiles +{ + public class Foobar2000Profile : DefaultProfile + { + public Foobar2000Profile() + { + Name = "foobar2000"; + + Identification = new DeviceIdentification + { + FriendlyName = @"foobar", + + Headers = new[] + { + new HttpHeaderInfo + { + Name = "User-Agent", + Value = "foobar", + Match = HeaderMatchType.Substring + } + } + }; + } + } +} diff --git a/MediaBrowser.Dlna/Profiles/SamsungSmartTvProfile.cs b/MediaBrowser.Dlna/Profiles/SamsungSmartTvProfile.cs index fa6b1201ab..fbbb7a594a 100644 --- a/MediaBrowser.Dlna/Profiles/SamsungSmartTvProfile.cs +++ b/MediaBrowser.Dlna/Profiles/SamsungSmartTvProfile.cs @@ -302,6 +302,13 @@ namespace MediaBrowser.Dlna.Profiles MediaProfiles = new[] { + new MediaProfile + { + Container = "avi", + MimeType = "video/x-msvideo", + Type = DlnaProfileType.Video + }, + new MediaProfile { Container = "mkv", diff --git a/MediaBrowser.Dlna/Profiles/SonyBlurayPlayer2013Profile.cs b/MediaBrowser.Dlna/Profiles/SonyBlurayPlayer2013Profile.cs index 49aa47027a..cec29b4182 100644 --- a/MediaBrowser.Dlna/Profiles/SonyBlurayPlayer2013Profile.cs +++ b/MediaBrowser.Dlna/Profiles/SonyBlurayPlayer2013Profile.cs @@ -6,6 +6,8 @@ namespace MediaBrowser.Dlna.Profiles { public SonyBlurayPlayer2013Profile() { + Name = "Sony Blu-ray Player 2013"; + Identification = new DeviceIdentification { FriendlyName = @"Blu-ray Disc Player", diff --git a/MediaBrowser.Dlna/Profiles/SonyBlurayPlayerProfile.cs b/MediaBrowser.Dlna/Profiles/SonyBlurayPlayerProfile.cs index 5121726706..2c678b11f0 100644 --- a/MediaBrowser.Dlna/Profiles/SonyBlurayPlayerProfile.cs +++ b/MediaBrowser.Dlna/Profiles/SonyBlurayPlayerProfile.cs @@ -6,6 +6,8 @@ namespace MediaBrowser.Dlna.Profiles { public SonyBlurayPlayerProfile() { + Name = "Sony Blu-ray Player"; + Identification = new DeviceIdentification { FriendlyName = @"Blu-ray Disc Player", diff --git a/MediaBrowser.Dlna/Server/Headers.cs b/MediaBrowser.Dlna/Server/Headers.cs index 859ae7fbf2..2bd1a72f7b 100644 --- a/MediaBrowser.Dlna/Server/Headers.cs +++ b/MediaBrowser.Dlna/Server/Headers.cs @@ -13,7 +13,7 @@ namespace MediaBrowser.Dlna.Server private readonly Dictionary _dict = new Dictionary(); private readonly static Regex Validator = new Regex(@"^[a-z\d][a-z\d_.-]+$", RegexOptions.Compiled | RegexOptions.IgnoreCase); - protected Headers(bool asIs) + public Headers(bool asIs) { _asIs = asIs; } diff --git a/MediaBrowser.Dlna/Server/RawHeaders.cs b/MediaBrowser.Dlna/Server/RawHeaders.cs deleted file mode 100644 index f57e6b9f3d..0000000000 --- a/MediaBrowser.Dlna/Server/RawHeaders.cs +++ /dev/null @@ -1,16 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; - -namespace MediaBrowser.Dlna.Server -{ - public class RawHeaders : Headers - { - public RawHeaders() - : base(true) - { - } - } -} diff --git a/MediaBrowser.Dlna/Server/SsdpHandler.cs b/MediaBrowser.Dlna/Server/SsdpHandler.cs index 63c2abbec4..64c1118196 100644 --- a/MediaBrowser.Dlna/Server/SsdpHandler.cs +++ b/MediaBrowser.Dlna/Server/SsdpHandler.cs @@ -96,7 +96,7 @@ namespace MediaBrowser.Dlna.Server { break; } - var parts = line.Split(new char[] { ':' }, 2); + var parts = line.Split(new[] { ':' }, 2); headers[parts[0]] = parts[1].Trim(); } @@ -148,7 +148,7 @@ namespace MediaBrowser.Dlna.Server private void SendSearchResponse(IPEndPoint endpoint, UpnpDevice dev) { - var headers = new RawHeaders(); + var headers = new Headers(true); headers.Add("CACHE-CONTROL", "max-age = 600"); headers.Add("DATE", DateTime.Now.ToString("R")); headers.Add("EXT", ""); @@ -188,7 +188,7 @@ namespace MediaBrowser.Dlna.Server private void NotifyDevice(UpnpDevice dev, string type, bool sticky) { _logger.Debug("NotifyDevice"); - var headers = new RawHeaders(); + var headers = new Headers(true); headers.Add("HOST", "239.255.255.250:1900"); headers.Add("CACHE-CONTROL", "max-age = 600"); headers.Add("LOCATION", dev.Descriptor.ToString()); diff --git a/MediaBrowser.Dlna/PlayTo/SsdpHelper.cs b/MediaBrowser.Dlna/Ssdp/SsdpHelper.cs similarity index 57% rename from MediaBrowser.Dlna/PlayTo/SsdpHelper.cs rename to MediaBrowser.Dlna/Ssdp/SsdpHelper.cs index d07a7679f0..b22db781ad 100644 --- a/MediaBrowser.Dlna/PlayTo/SsdpHelper.cs +++ b/MediaBrowser.Dlna/Ssdp/SsdpHelper.cs @@ -1,8 +1,9 @@ using System; -using System.Linq; +using System.Collections.Generic; +using System.IO; using System.Text; -namespace MediaBrowser.Dlna.PlayTo +namespace MediaBrowser.Dlna.Ssdp { public class SsdpHelper { @@ -29,28 +30,29 @@ namespace MediaBrowser.Dlna.PlayTo /// /// The data. /// - public static Uri ParseSsdpResponse(string data) + public static Dictionary ParseSsdpResponse(byte[] data) { - var res = (from line in data.Split(new[] { '\r', '\n' }) - where line.ToLowerInvariant().StartsWith("location:") - select line).FirstOrDefault(); + var headers = new Dictionary(StringComparer.OrdinalIgnoreCase); - return !string.IsNullOrEmpty(res) ? new Uri(res.Substring(9).Trim()) : null; - } + using (var reader = new StreamReader(new MemoryStream(data), Encoding.ASCII)) + { + for (var line = reader.ReadLine(); line != null; line = reader.ReadLine()) + { + line = line.Trim(); + if (string.IsNullOrEmpty(line)) + { + break; + } + var parts = line.Split(new[] { ':' }, 2); - /// - /// Parses data into SSDP event. - /// - /// The data. - /// - [Obsolete("Not yet used", true)] - public static string ParseSsdpEvent(string data) - { - var sid = (from line in data.Split(new[] { '\r', '\n' }) - where line.ToLowerInvariant().StartsWith("sid:") - select line).FirstOrDefault(); - - return data; + if (parts.Length == 2) + { + headers[parts[0]] = parts[1].Trim(); + } + } + } + + return headers; } } } diff --git a/MediaBrowser.Providers/Savers/MovieXmlSaver.cs b/MediaBrowser.Providers/Savers/MovieXmlSaver.cs index 5957938543..9a31fd0912 100644 --- a/MediaBrowser.Providers/Savers/MovieXmlSaver.cs +++ b/MediaBrowser.Providers/Savers/MovieXmlSaver.cs @@ -3,7 +3,6 @@ using MediaBrowser.Controller.Entities.Movies; using MediaBrowser.Controller.Entities.TV; using MediaBrowser.Controller.Library; using MediaBrowser.Controller.Persistence; -using MediaBrowser.Model.Entities; using System.Collections.Generic; using System.Globalization; using System.IO; @@ -75,16 +74,6 @@ namespace MediaBrowser.Providers.Savers XmlSaverHelpers.AddCommonNodes(video, builder); - if (video.CommunityRating.HasValue) - { - builder.Append("" + SecurityElement.Escape(video.CommunityRating.Value.ToString(UsCulture)) + ""); - } - - if (!string.IsNullOrEmpty(video.Overview)) - { - builder.Append(""); - } - var musicVideo = item as MusicVideo; if (musicVideo != null) @@ -117,8 +106,12 @@ namespace MediaBrowser.Providers.Savers XmlSaverHelpers.Save(builder, xmlFilePath, new List { + // Deprecated. No longer saving in this field. "IMDBrating", + + // Deprecated. No longer saving in this field. "Description", + "Artist", "Album", "TmdbCollectionName" diff --git a/MediaBrowser.Providers/Savers/SeriesXmlSaver.cs b/MediaBrowser.Providers/Savers/SeriesXmlSaver.cs index e69f2e0850..a7ed55e5dd 100644 --- a/MediaBrowser.Providers/Savers/SeriesXmlSaver.cs +++ b/MediaBrowser.Providers/Savers/SeriesXmlSaver.cs @@ -60,11 +60,6 @@ namespace MediaBrowser.Providers.Savers builder.Append("" + SecurityElement.Escape(tvdb) + ""); } - if (!string.IsNullOrEmpty(item.Name)) - { - builder.Append("" + SecurityElement.Escape(item.Name) + ""); - } - if (series.Status.HasValue) { builder.Append("" + SecurityElement.Escape(series.Status.Value.ToString()) + ""); @@ -111,7 +106,6 @@ namespace MediaBrowser.Providers.Savers XmlSaverHelpers.Save(builder, xmlFilePath, new List { "id", - "SeriesName", "Status", "Network", "Airs_Time", @@ -120,6 +114,10 @@ namespace MediaBrowser.Providers.Savers // Don't preserve old series node "Series", + + "SeriesName", + + // Deprecated. No longer saving in this field. "AnimeSeriesIndex" }); } diff --git a/MediaBrowser.Providers/Savers/XmlSaverHelpers.cs b/MediaBrowser.Providers/Savers/XmlSaverHelpers.cs index 391ab7cfd9..6d681197e5 100644 --- a/MediaBrowser.Providers/Savers/XmlSaverHelpers.cs +++ b/MediaBrowser.Providers/Savers/XmlSaverHelpers.cs @@ -28,7 +28,10 @@ namespace MediaBrowser.Providers.Savers "AwardSummary", "BirthDate", "Budget", + + // Deprecated. No longer saving in this field. "certification", + "Chapters", "ContentRating", "CustomRating", @@ -40,22 +43,31 @@ namespace MediaBrowser.Providers.Savers "Genres", "Genre", "GamesDbId", + + // Deprecated. No longer saving in this field. "IMDB_ID", + "IMDB", + + // Deprecated. No longer saving in this field. "IMDbId", + "Language", "LocalTitle", "LockData", "LockedFields", "Format3D", "Metascore", + + // Deprecated. No longer saving in this field. "MPAARating", + "MusicBrainzArtistId", "MusicBrainzAlbumArtistId", "MusicBrainzAlbumId", "MusicBrainzReleaseGroupId", - // Old - not used anymore + // Deprecated. No longer saving in this field. "MusicbrainzId", "Overview", @@ -67,15 +79,24 @@ namespace MediaBrowser.Providers.Savers "Revenue", "RottenTomatoesId", "RunningTime", + + // Deprecated. No longer saving in this field. "Runtime", + "SortTitle", "Studios", "Tags", + + // Deprecated. No longer saving in this field. "TagLine", + "Taglines", "TMDbCollectionId", "TMDbId", + + // Deprecated. No longer saving in this field. "Trailer", + "Trailers", "TVcomId", "TvDbId", @@ -207,8 +228,6 @@ namespace MediaBrowser.Providers.Savers if (!string.IsNullOrEmpty(item.OfficialRating)) { builder.Append("" + SecurityElement.Escape(item.OfficialRating) + ""); - builder.Append("" + SecurityElement.Escape(item.OfficialRating) + ""); - builder.Append("" + SecurityElement.Escape(item.OfficialRating) + ""); } builder.Append("" + SecurityElement.Escape(item.DateCreated.ToLocalTime().ToString("G")) + ""); @@ -376,16 +395,13 @@ namespace MediaBrowser.Providers.Savers var timespan = TimeSpan.FromTicks(runTimeTicks.Value); builder.Append("" + Convert.ToInt32(timespan.TotalMinutes).ToString(UsCulture) + ""); - builder.Append("" + Convert.ToInt32(timespan.TotalMinutes).ToString(UsCulture) + ""); } var imdb = item.GetProviderId(MetadataProviders.Imdb); if (!string.IsNullOrEmpty(imdb)) { - builder.Append("" + SecurityElement.Escape(imdb) + ""); builder.Append("" + SecurityElement.Escape(imdb) + ""); - builder.Append("" + SecurityElement.Escape(imdb) + ""); } var tmdb = item.GetProviderId(MetadataProviders.Tmdb); diff --git a/MediaBrowser.Providers/TV/SeriesXmlParser.cs b/MediaBrowser.Providers/TV/SeriesXmlParser.cs index 0c220031c1..9f68ad7a4e 100644 --- a/MediaBrowser.Providers/TV/SeriesXmlParser.cs +++ b/MediaBrowser.Providers/TV/SeriesXmlParser.cs @@ -90,6 +90,8 @@ namespace MediaBrowser.Providers.TV break; } case "SeriesName": + // TODO: Deprecate in mid-2014 + // No longer saving this tag but will still read it for a while item.Name = reader.ReadElementContentAsString(); break; diff --git a/MediaBrowser.Server.Implementations/MediaEncoder/MediaEncoder.cs b/MediaBrowser.Server.Implementations/MediaEncoder/MediaEncoder.cs index 02c629906c..fcfe98a46e 100644 --- a/MediaBrowser.Server.Implementations/MediaEncoder/MediaEncoder.cs +++ b/MediaBrowser.Server.Implementations/MediaEncoder/MediaEncoder.cs @@ -851,7 +851,7 @@ namespace MediaBrowser.Server.Implementations.MediaEncoder } // Use ffmpeg to sample 100 (we can drop this if required using thumbnail=50 for 50 frames) frames and pick the best thumbnail. Have a fall back just in case. - var args = useIFrame ? string.Format("-i {0} -threads 0 -v quiet -vframes 1 -vf \"{2},thumbnail=20\" -f image2 \"{1}\"", inputPath, "-", vf) : + var args = useIFrame ? string.Format("-i {0} -threads 0 -v quiet -vframes 1 -vf \"thumbnail,{2}\" -f image2 \"{1}\"", inputPath, "-", vf) : string.Format("-i {0} -threads 0 -v quiet -vframes 1 -vf \"{2}\" -f image2 \"{1}\"", inputPath, "-", vf); var probeSize = GetProbeSizeArgument(type);