mirror of
				https://github.com/jellyfin/jellyfin.git
				synced 2025-11-03 19:17:24 -05:00 
			
		
		
		
	implement dlna headers
This commit is contained in:
		
							parent
							
								
									1644d45dac
								
							
						
					
					
						commit
						f245fffad1
					
				@ -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; }
 | 
			
		||||
 | 
			
		||||
        /// <summary>
 | 
			
		||||
        /// Initializes a new instance of the <see cref="BaseStreamingService" /> class.
 | 
			
		||||
@ -77,8 +79,9 @@ namespace MediaBrowser.Api.Playback
 | 
			
		||||
        /// <param name="dtoService">The dto service.</param>
 | 
			
		||||
        /// <param name="fileSystem">The file system.</param>
 | 
			
		||||
        /// <param name="itemRepository">The item repository.</param>
 | 
			
		||||
        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();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        /// <summary>
 | 
			
		||||
@ -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<string, string>();
 | 
			
		||||
 | 
			
		||||
            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");
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
        /// <summary>
 | 
			
		||||
        /// Adds the dlna headers.
 | 
			
		||||
        /// </summary>
 | 
			
		||||
        /// <param name="state">The state.</param>
 | 
			
		||||
        /// <param name="responseHeaders">The response headers.</param>
 | 
			
		||||
        /// <param name="isStaticallyStreamed">if set to <c>true</c> [is statically streamed].</param>
 | 
			
		||||
        /// <returns><c>true</c> if XXXX, <c>false</c> otherwise</returns>
 | 
			
		||||
        protected void AddDlnaHeaders(StreamState state, IDictionary<string, string> 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);
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        /// <summary>
 | 
			
		||||
        /// Enforces the resolution limit.
 | 
			
		||||
        /// </summary>
 | 
			
		||||
@ -1605,7 +1755,7 @@ namespace MediaBrowser.Api.Playback
 | 
			
		||||
                return "vorbis";
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            return null;
 | 
			
		||||
            return "copy";
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        /// <summary>
 | 
			
		||||
 | 
			
		||||
@ -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
 | 
			
		||||
    /// </summary>
 | 
			
		||||
    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)
 | 
			
		||||
        {
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -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)
 | 
			
		||||
        {
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -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
 | 
			
		||||
    /// </summary>
 | 
			
		||||
    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)
 | 
			
		||||
        {
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -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
 | 
			
		||||
    /// </summary>
 | 
			
		||||
    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)
 | 
			
		||||
        {
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -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;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        /// <summary>
 | 
			
		||||
        /// Adds the dlna headers.
 | 
			
		||||
        /// </summary>
 | 
			
		||||
        /// <param name="state">The state.</param>
 | 
			
		||||
        /// <param name="responseHeaders">The response headers.</param>
 | 
			
		||||
        /// <param name="isStaticallyStreamed">if set to <c>true</c> [is statically streamed].</param>
 | 
			
		||||
        /// <returns><c>true</c> if XXXX, <c>false</c> otherwise</returns>
 | 
			
		||||
        private void AddDlnaHeaders(StreamState state, IDictionary<string, string> 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);
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        /// <summary>
 | 
			
		||||
        /// Gets the type of the transcoding job.
 | 
			
		||||
        /// </summary>
 | 
			
		||||
 | 
			
		||||
@ -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
 | 
			
		||||
    /// </summary>
 | 
			
		||||
    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)
 | 
			
		||||
        {
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -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);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
@ -41,9 +41,7 @@ namespace MediaBrowser.Controller.Dlna
 | 
			
		||||
        /// <summary>
 | 
			
		||||
        /// Gets or sets the manufacturer.
 | 
			
		||||
        /// </summary>
 | 
			
		||||
        /// <value>
 | 
			
		||||
        /// The manufacturer.
 | 
			
		||||
        /// </value>
 | 
			
		||||
        /// <value>The manufacturer.</value>
 | 
			
		||||
        public string Manufacturer { get; set; }
 | 
			
		||||
        /// <summary>
 | 
			
		||||
        /// Gets or sets the manufacturer URL.
 | 
			
		||||
 | 
			
		||||
@ -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
 | 
			
		||||
        /// <value>The name.</value>
 | 
			
		||||
        public string Name { get; set; }
 | 
			
		||||
 | 
			
		||||
        /// <summary>
 | 
			
		||||
        /// Gets or sets the type of the client.
 | 
			
		||||
        /// </summary>
 | 
			
		||||
        /// <value>The type of the client.</value>
 | 
			
		||||
        public string ClientType { get; set; }
 | 
			
		||||
 | 
			
		||||
        /// <summary>
 | 
			
		||||
        /// Gets or sets the transcoding profiles.
 | 
			
		||||
        /// </summary>
 | 
			
		||||
@ -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;
 | 
			
		||||
            });
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -16,6 +16,13 @@ namespace MediaBrowser.Controller.Dlna
 | 
			
		||||
        /// <returns>DlnaProfile.</returns>
 | 
			
		||||
        DeviceProfile GetDefaultProfile();
 | 
			
		||||
 | 
			
		||||
        /// <summary>
 | 
			
		||||
        /// Gets the profile.
 | 
			
		||||
        /// </summary>
 | 
			
		||||
        /// <param name="headers">The headers.</param>
 | 
			
		||||
        /// <returns>DeviceProfile.</returns>
 | 
			
		||||
        DeviceProfile GetProfile(IDictionary<string,string> headers);
 | 
			
		||||
 | 
			
		||||
        /// <summary>
 | 
			
		||||
        /// Gets the profile.
 | 
			
		||||
        /// </summary>
 | 
			
		||||
 | 
			
		||||
@ -19,6 +19,11 @@ namespace MediaBrowser.Controller.Dlna
 | 
			
		||||
        {
 | 
			
		||||
            Conditions = new ProfileCondition[] {};
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public List<string> GetContainers()
 | 
			
		||||
        {
 | 
			
		||||
            return (Container ?? string.Empty).Split(',').Where(i => !string.IsNullOrWhiteSpace(i)).ToList();
 | 
			
		||||
        }
 | 
			
		||||
        
 | 
			
		||||
        public List<string> GetAudioCodecs()
 | 
			
		||||
        {
 | 
			
		||||
 | 
			
		||||
@ -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<string> GetAudioCodecs()
 | 
			
		||||
        {
 | 
			
		||||
            return (AudioCodec ?? string.Empty).Split(',').Where(i => !string.IsNullOrWhiteSpace(i)).ToList();
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public class TranscodingSetting
 | 
			
		||||
 | 
			
		||||
@ -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
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        /// <summary>
 | 
			
		||||
        /// Fetches from parental rating node.
 | 
			
		||||
        /// </summary>
 | 
			
		||||
        /// <param name="reader">The reader.</param>
 | 
			
		||||
        /// <param name="item">The item.</param>
 | 
			
		||||
        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;
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        /// <summary>
 | 
			
		||||
        /// Gets the persons from XML node.
 | 
			
		||||
        /// </summary>
 | 
			
		||||
 | 
			
		||||
@ -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<string, string> headers)
 | 
			
		||||
        {
 | 
			
		||||
            return GetProfiles().FirstOrDefault(i => IsMatch(headers, i.Identification)) ??
 | 
			
		||||
                GetDefaultProfile();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private bool IsMatch(IDictionary<string, string> headers, DeviceIdentification profileInfo)
 | 
			
		||||
        {
 | 
			
		||||
            return profileInfo.Headers.Any(i => IsMatch(headers, i));
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private bool IsMatch(IDictionary<string, string> 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;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@ -61,7 +61,6 @@
 | 
			
		||||
    <Compile Include="PlayTo\DeviceService.cs" />
 | 
			
		||||
    <Compile Include="PlayTo\DidlBuilder.cs" />
 | 
			
		||||
    <Compile Include="PlayTo\DlnaController.cs" />
 | 
			
		||||
    <Compile Include="PlayTo\DlnaControllerFactory.cs" />
 | 
			
		||||
    <Compile Include="PlayTo\Extensions.cs" />
 | 
			
		||||
    <Compile Include="PlayTo\PlaylistItem.cs">
 | 
			
		||||
      <SubType>Code</SubType>
 | 
			
		||||
@ -70,7 +69,8 @@
 | 
			
		||||
    <Compile Include="PlayTo\PlayToManager.cs" />
 | 
			
		||||
    <Compile Include="PlayTo\PlayToServerEntryPoint.cs" />
 | 
			
		||||
    <Compile Include="PlayTo\ServiceAction.cs" />
 | 
			
		||||
    <Compile Include="PlayTo\SsdpHelper.cs" />
 | 
			
		||||
    <Compile Include="Profiles\Foobar2000Profile.cs" />
 | 
			
		||||
    <Compile Include="Ssdp\SsdpHelper.cs" />
 | 
			
		||||
    <Compile Include="PlayTo\SsdpHttpClient.cs" />
 | 
			
		||||
    <Compile Include="PlayTo\StateVariable.cs" />
 | 
			
		||||
    <Compile Include="PlayTo\StreamHelper.cs" />
 | 
			
		||||
@ -100,7 +100,6 @@
 | 
			
		||||
    <Compile Include="Properties\AssemblyInfo.cs" />
 | 
			
		||||
    <Compile Include="Server\DlnaServerEntryPoint.cs" />
 | 
			
		||||
    <Compile Include="Server\Headers.cs" />
 | 
			
		||||
    <Compile Include="Server\RawHeaders.cs" />
 | 
			
		||||
    <Compile Include="Server\SsdpHandler.cs" />
 | 
			
		||||
    <Compile Include="Server\UpnpDevice.cs" />
 | 
			
		||||
  </ItemGroup>
 | 
			
		||||
 | 
			
		||||
@ -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);
 | 
			
		||||
 | 
			
		||||
@ -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
 | 
			
		||||
            };
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
@ -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 = @"<item id=""{0}"" parentID=""{1}"" restricted=""1"" xmlns=""urn:schemas-upnp-org:metadata-1-0/DIDL-Lite/"">" + CRLF;
 | 
			
		||||
        internal const string DIDL_TITLE = @"  <dc:title xmlns:dc=""http://purl.org/dc/elements/1.1/"">{0}</dc:title>" + CRLF;
 | 
			
		||||
        internal const string DIDL_ARTIST = @"<upnp:artist xmlns:upnp=""urn:schemas-upnp-org:metadata-1-0/upnp/"">{0}</upnp:artist>" + CRLF;
 | 
			
		||||
        internal const string DIDL_ALBUM = @"<upnp:album xmlns:upnp=""urn:schemas-upnp-org:metadata-1-0/upnp/"">{0}</upnp:album>" + CRLF;
 | 
			
		||||
        internal const string DIDL_TRACKNUM = @"<upnp:originalTrackNumber xmlns:upnp=""urn:schemas-upnp-org:metadata-1-0/upnp/"">0</upnp:originalTrackNumber>" + CRLF;
 | 
			
		||||
        internal const string DIDL_VIDEOCLASS = @"  <upnp:class xmlns:upnp=""urn:schemas-upnp-org:metadata-1-0/upnp/"">object.item.videoItem</upnp:class>" + CRLF;
 | 
			
		||||
        internal const string DIDL_AUDIOCLASS = @"  <upnp:class xmlns:upnp=""urn:schemas-upnp-org:metadata-1-0/upnp/"">object.item.audioItem.musicTrack</upnp:class>" + CRLF;
 | 
			
		||||
        internal const string DIDL_IMAGE = @"  <upnp:albumArtURI dlna:profileID=""JPEG_TN"" xmlns:dlna=""urn:schemas-dlna-org:metadata-1-0/"" xmlns:upnp=""urn:schemas-upnp-org:metadata-1-0/upnp/"">{0}</upnp:albumArtURI>" + CRLF +
 | 
			
		||||
                                                @"  <upnp:icon xmlns:upnp=""urn:schemas-upnp-org:metadata-1-0/upnp/"">{0}</upnp:icon>" + CRLF;
 | 
			
		||||
        internal const string DIDL_RELEASEDATE = @"  <dc:date xmlns:dc=""http://purl.org/dc/elements/1.1/"">{0}</dc:date>" + CRLF;
 | 
			
		||||
        internal const string DIDL_GENRE = @"  <upnp:genre xmlns:upnp=""urn:schemas-upnp-org:metadata-1-0/upnp/"">{0}</upnp:genre>" + CRLF;
 | 
			
		||||
        internal const string DESCRIPTION = @"  <dc:description xmlns:dc=""http://purl.org/dc/elements/1.1/"">{0}</dc:description>" + CRLF;
 | 
			
		||||
        internal const string DIDL_VIDEO_RES = @"  <res bitrate=""{0}"" duration=""{1}"" protocolInfo=""http-get:*:video/x-msvideo:DLNA.ORG_PN=AVI;DLNA.ORG_OP=01;DLNA.ORG_CI=0;DLNA.ORG_FLAGS=01500000000000000000000000000000"" resolution=""{2}x{3}"" size=""0"">{4}</res>" + CRLF;
 | 
			
		||||
        internal const string DIDL_AUDIO_RES = @"  <res bitrate=""{0}"" duration=""{1}"" nrAudioChannels=""2"" protocolInfo=""http-get:*:audio/mp3:DLNA.ORG_OP=01;DLNA.ORG_CI=0;DLNA.ORG_FLAGS=01500000000000000000000000000000"" sampleFrequency=""{2}"" size=""0"">{3}</res>" + CRLF;
 | 
			
		||||
        internal const string DIDL_IMAGE_RES = @"  <res protocolInfo=""http-get:*:image/jpeg:DLNA.ORG_PN=JPEG_TN;DLNA.ORG_OP=00;DLNA.ORG_CI=1;DLNA.ORG_FLAGS=00D00000000000000000000000000000"" resolution=""212x320"">{0}</res>" + CRLF;
 | 
			
		||||
        internal const string DIDL_ALBUMIMAGE_RES = @"  <res protocolInfo=""http-get:*:image/jpeg:DLNA.ORG_PN=JPEG_TN;DLNA.ORG_OP=00;DLNA.ORG_CI=1;DLNA.ORG_FLAGS=00D00000000000000000000000000000"" resolution=""320x320"">{0}</res>" + CRLF;
 | 
			
		||||
        internal const string DIDL_RATING = @"  <upnp:rating xmlns:upnp=""urn:schemas-upnp-org:metadata-1-0/upnp/"">{0}</upnp:rating>" + CRLF;
 | 
			
		||||
        internal const string DIDL_END = "</item>";
 | 
			
		||||
 | 
			
		||||
        #endregion
 | 
			
		||||
        const string DIDL_START = @"<item id=""{0}"" parentID=""{1}"" restricted=""1"" xmlns=""urn:schemas-upnp-org:metadata-1-0/DIDL-Lite/"">" + CRLF;
 | 
			
		||||
        const string DIDL_TITLE = @"  <dc:title xmlns:dc=""http://purl.org/dc/elements/1.1/"">{0}</dc:title>" + CRLF;
 | 
			
		||||
        const string DIDL_ARTIST = @"<upnp:artist xmlns:upnp=""urn:schemas-upnp-org:metadata-1-0/upnp/"">{0}</upnp:artist>" + CRLF;
 | 
			
		||||
        const string DIDL_ALBUM = @"<upnp:album xmlns:upnp=""urn:schemas-upnp-org:metadata-1-0/upnp/"">{0}</upnp:album>" + CRLF;
 | 
			
		||||
        const string DIDL_TRACKNUM = @"<upnp:originalTrackNumber xmlns:upnp=""urn:schemas-upnp-org:metadata-1-0/upnp/"">{0}</upnp:originalTrackNumber>" + CRLF;
 | 
			
		||||
        const string DIDL_VIDEOCLASS = @"  <upnp:class xmlns:upnp=""urn:schemas-upnp-org:metadata-1-0/upnp/"">object.item.videoItem</upnp:class>" + CRLF;
 | 
			
		||||
        const string DIDL_AUDIOCLASS = @"  <upnp:class xmlns:upnp=""urn:schemas-upnp-org:metadata-1-0/upnp/"">object.item.audioItem.musicTrack</upnp:class>" + CRLF;
 | 
			
		||||
        const string DIDL_IMAGE = @"  <upnp:albumArtURI dlna:profileID=""JPEG_TN"" xmlns:dlna=""urn:schemas-dlna-org:metadata-1-0/"" xmlns:upnp=""urn:schemas-upnp-org:metadata-1-0/upnp/"">{0}</upnp:albumArtURI>" + CRLF +
 | 
			
		||||
                                               @"  <upnp:icon xmlns:upnp=""urn:schemas-upnp-org:metadata-1-0/upnp/"">{0}</upnp:icon>" + CRLF;
 | 
			
		||||
        const string DIDL_RELEASEDATE = @"  <dc:date xmlns:dc=""http://purl.org/dc/elements/1.1/"">{0}</dc:date>" + CRLF;
 | 
			
		||||
        const string DIDL_GENRE = @"  <upnp:genre xmlns:upnp=""urn:schemas-upnp-org:metadata-1-0/upnp/"">{0}</upnp:genre>" + CRLF;
 | 
			
		||||
        const string DESCRIPTION = @"  <dc:description xmlns:dc=""http://purl.org/dc/elements/1.1/"">{0}</dc:description>" + CRLF;
 | 
			
		||||
        const string DIDL_VIDEO_RES = @"  <res bitrate=""{0}"" duration=""{1}"" protocolInfo=""http-get:*:video/x-msvideo:DLNA.ORG_PN=AVI;DLNA.ORG_OP=01;DLNA.ORG_CI=0;DLNA.ORG_FLAGS=01500000000000000000000000000000"" resolution=""{2}x{3}"" size=""0"">{4}</res>" + CRLF;
 | 
			
		||||
        const string DIDL_AUDIO_RES = @"  <res bitrate=""{0}"" duration=""{1}"" nrAudioChannels=""2"" protocolInfo=""http-get:*:audio/mp3:DLNA.ORG_OP=01;DLNA.ORG_CI=0;DLNA.ORG_FLAGS=01500000000000000000000000000000"" sampleFrequency=""{2}"" size=""0"">{3}</res>" + CRLF;
 | 
			
		||||
        const string DIDL_IMAGE_RES = @"  <res protocolInfo=""http-get:*:image/jpeg:DLNA.ORG_PN=JPEG_TN;DLNA.ORG_OP=00;DLNA.ORG_CI=1;DLNA.ORG_FLAGS=00D00000000000000000000000000000"" resolution=""212x320"">{0}</res>" + CRLF;
 | 
			
		||||
        const string DIDL_ALBUMIMAGE_RES = @"  <res protocolInfo=""http-get:*:image/jpeg:DLNA.ORG_PN=JPEG_TN;DLNA.ORG_OP=00;DLNA.ORG_CI=1;DLNA.ORG_FLAGS=00D00000000000000000000000000000"" resolution=""320x320"">{0}</res>" + CRLF;
 | 
			
		||||
        const string DIDL_RATING = @"  <upnp:rating xmlns:upnp=""urn:schemas-upnp-org:metadata-1-0/upnp/"">{0}</upnp:rating>" + CRLF;
 | 
			
		||||
        const string DIDL_END = "</item>";
 | 
			
		||||
 | 
			
		||||
        /// <summary>
 | 
			
		||||
        /// Builds a Didl MetaData object for the specified dto.
 | 
			
		||||
@ -44,7 +40,7 @@ namespace MediaBrowser.Dlna.PlayTo
 | 
			
		||||
        /// <param name="streamUrl">The stream URL.</param>
 | 
			
		||||
        /// <param name="streams">The streams.</param>
 | 
			
		||||
        /// <returns>System.String.</returns>
 | 
			
		||||
        internal static string Build(BaseItem dto, string userId, string serverAddress, string streamUrl, IEnumerable<MediaStream> streams)
 | 
			
		||||
        public static string Build(BaseItem dto, string userId, string serverAddress, string streamUrl, IEnumerable<MediaStream> 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<MediaStream> 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<MediaStream> 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
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -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<string> { "Audio", "Video" } }).ConfigureAwait(false);
 | 
			
		||||
                await _sessionManager.OnPlaybackStart(new PlaybackInfo
 | 
			
		||||
                {
 | 
			
		||||
                    Item = _currentItem, 
 | 
			
		||||
                    SessionId = _session.Id, 
 | 
			
		||||
                    CanSeek = true, 
 | 
			
		||||
                    QueueableMediaTypes = new List<string> { "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;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
@ -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;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@ -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<string,string> 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);
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        /// <summary>
 | 
			
		||||
        /// Gets the profile settings.
 | 
			
		||||
        /// </summary>
 | 
			
		||||
        /// <param name="deviceProperties">The device properties.</param>
 | 
			
		||||
        /// <returns>The TranscodeSettings for the device</returns>
 | 
			
		||||
        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;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -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; }
 | 
			
		||||
 | 
			
		||||
@ -162,7 +162,8 @@ namespace MediaBrowser.Dlna.PlayTo
 | 
			
		||||
 | 
			
		||||
        private void ApplyTranscodingConditions(PlaylistItem item, IEnumerable<ProfileCondition> 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;
 | 
			
		||||
 | 
			
		||||
@ -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<XDocument> GetDataAsync(Uri url)
 | 
			
		||||
        public async Task<XDocument> 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<HttpResponseInfo> PostSoapDataAsync(Uri url, string soapAction, string postData, string header = null, int timeOut = 20000)
 | 
			
		||||
        private Task<HttpResponseInfo> 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
 | 
			
		||||
            };
 | 
			
		||||
 | 
			
		||||
@ -43,15 +43,10 @@ namespace MediaBrowser.Dlna.PlayTo
 | 
			
		||||
        /// </summary>
 | 
			
		||||
        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<string>
 | 
			
		||||
            {
 | 
			
		||||
                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
 | 
			
		||||
            };
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -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";
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										27
									
								
								MediaBrowser.Dlna/Profiles/Foobar2000Profile.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										27
									
								
								MediaBrowser.Dlna/Profiles/Foobar2000Profile.cs
									
									
									
									
									
										Normal file
									
								
							@ -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
 | 
			
		||||
                   }
 | 
			
		||||
               }
 | 
			
		||||
            };
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@ -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",
 | 
			
		||||
 | 
			
		||||
@ -6,6 +6,8 @@ namespace MediaBrowser.Dlna.Profiles
 | 
			
		||||
    {
 | 
			
		||||
        public SonyBlurayPlayer2013Profile()
 | 
			
		||||
        {
 | 
			
		||||
            Name = "Sony Blu-ray Player 2013";
 | 
			
		||||
 | 
			
		||||
            Identification = new DeviceIdentification
 | 
			
		||||
            {
 | 
			
		||||
                FriendlyName = @"Blu-ray Disc Player",
 | 
			
		||||
 | 
			
		||||
@ -6,6 +6,8 @@ namespace MediaBrowser.Dlna.Profiles
 | 
			
		||||
    {
 | 
			
		||||
        public SonyBlurayPlayerProfile()
 | 
			
		||||
        {
 | 
			
		||||
            Name = "Sony Blu-ray Player";
 | 
			
		||||
 | 
			
		||||
            Identification = new DeviceIdentification
 | 
			
		||||
            {
 | 
			
		||||
                FriendlyName = @"Blu-ray Disc Player",
 | 
			
		||||
 | 
			
		||||
@ -13,7 +13,7 @@ namespace MediaBrowser.Dlna.Server
 | 
			
		||||
        private readonly Dictionary<string, string> _dict = new Dictionary<string, string>();
 | 
			
		||||
        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;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
@ -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)
 | 
			
		||||
        {
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@ -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());
 | 
			
		||||
 | 
			
		||||
@ -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
 | 
			
		||||
        /// </summary>
 | 
			
		||||
        /// <param name="data">The data.</param>
 | 
			
		||||
        /// <returns></returns>
 | 
			
		||||
        public static Uri ParseSsdpResponse(string data)
 | 
			
		||||
        public static Dictionary<string,string> 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<string, string>(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);
 | 
			
		||||
 | 
			
		||||
        /// <summary>
 | 
			
		||||
        /// Parses data into SSDP event.        
 | 
			
		||||
        /// </summary>
 | 
			
		||||
        /// <param name="data">The data.</param>
 | 
			
		||||
        /// <returns></returns>
 | 
			
		||||
        [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;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@ -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("<IMDBrating>" + SecurityElement.Escape(video.CommunityRating.Value.ToString(UsCulture)) + "</IMDBrating>");
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            if (!string.IsNullOrEmpty(video.Overview))
 | 
			
		||||
            {
 | 
			
		||||
                builder.Append("<Description><![CDATA[" + video.Overview + "]]></Description>");
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            var musicVideo = item as MusicVideo;
 | 
			
		||||
 | 
			
		||||
            if (musicVideo != null)
 | 
			
		||||
@ -117,8 +106,12 @@ namespace MediaBrowser.Providers.Savers
 | 
			
		||||
 | 
			
		||||
            XmlSaverHelpers.Save(builder, xmlFilePath, new List<string>
 | 
			
		||||
                {
 | 
			
		||||
                    // Deprecated. No longer saving in this field.
 | 
			
		||||
                    "IMDBrating",
 | 
			
		||||
                    
 | 
			
		||||
                    // Deprecated. No longer saving in this field.
 | 
			
		||||
                    "Description",
 | 
			
		||||
 | 
			
		||||
                    "Artist",
 | 
			
		||||
                    "Album",
 | 
			
		||||
                    "TmdbCollectionName"
 | 
			
		||||
 | 
			
		||||
@ -60,11 +60,6 @@ namespace MediaBrowser.Providers.Savers
 | 
			
		||||
                builder.Append("<id>" + SecurityElement.Escape(tvdb) + "</id>");
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            if (!string.IsNullOrEmpty(item.Name))
 | 
			
		||||
            {
 | 
			
		||||
                builder.Append("<SeriesName>" + SecurityElement.Escape(item.Name) + "</SeriesName>");
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            if (series.Status.HasValue)
 | 
			
		||||
            {
 | 
			
		||||
                builder.Append("<Status>" + SecurityElement.Escape(series.Status.Value.ToString()) + "</Status>");
 | 
			
		||||
@ -111,7 +106,6 @@ namespace MediaBrowser.Providers.Savers
 | 
			
		||||
            XmlSaverHelpers.Save(builder, xmlFilePath, new List<string>
 | 
			
		||||
                {
 | 
			
		||||
                    "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"
 | 
			
		||||
                });
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
@ -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("<ContentRating>" + SecurityElement.Escape(item.OfficialRating) + "</ContentRating>");
 | 
			
		||||
                builder.Append("<MPAARating>" + SecurityElement.Escape(item.OfficialRating) + "</MPAARating>");
 | 
			
		||||
                builder.Append("<certification>" + SecurityElement.Escape(item.OfficialRating) + "</certification>");
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            builder.Append("<Added>" + SecurityElement.Escape(item.DateCreated.ToLocalTime().ToString("G")) + "</Added>");
 | 
			
		||||
@ -376,16 +395,13 @@ namespace MediaBrowser.Providers.Savers
 | 
			
		||||
                var timespan = TimeSpan.FromTicks(runTimeTicks.Value);
 | 
			
		||||
 | 
			
		||||
                builder.Append("<RunningTime>" + Convert.ToInt32(timespan.TotalMinutes).ToString(UsCulture) + "</RunningTime>");
 | 
			
		||||
                builder.Append("<Runtime>" + Convert.ToInt32(timespan.TotalMinutes).ToString(UsCulture) + "</Runtime>");
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            var imdb = item.GetProviderId(MetadataProviders.Imdb);
 | 
			
		||||
 | 
			
		||||
            if (!string.IsNullOrEmpty(imdb))
 | 
			
		||||
            {
 | 
			
		||||
                builder.Append("<IMDB_ID>" + SecurityElement.Escape(imdb) + "</IMDB_ID>");
 | 
			
		||||
                builder.Append("<IMDB>" + SecurityElement.Escape(imdb) + "</IMDB>");
 | 
			
		||||
                builder.Append("<IMDbId>" + SecurityElement.Escape(imdb) + "</IMDbId>");
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            var tmdb = item.GetProviderId(MetadataProviders.Tmdb);
 | 
			
		||||
 | 
			
		||||
@ -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;
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -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);
 | 
			
		||||
 | 
			
		||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user