/// <summary>
        /// Adds fields used by both items and folders
        /// </summary>
        /// <param name="item">The item.</param>
        /// <param name="element">The element.</param>
        /// <param name="filter">The filter.</param>
        private void AddCommonFields(BaseItem item, XmlElement element, Filter filter)
        {
            if (filter.Contains("dc:date"))
            {
                if (item.PremiereDate.HasValue)
                {
                    AddValue(element, "dc", "date", item.PremiereDate.Value.ToString("o"), NS_DC);
                }
            }

            foreach (var genre in item.Genres)
            {
                AddValue(element, "upnp", "genre", genre, NS_UPNP);
            }

            foreach (var studio in item.Studios)
            {
                AddValue(element, "upnp", "publisher", studio, NS_UPNP);
            }

            if (filter.Contains("dc:title"))
            {
                AddValue(element, "dc", "title", item.Name, NS_DC);
            }

            if (filter.Contains("dc:description"))
            {
                if (!string.IsNullOrWhiteSpace(item.Overview))
                {
                    AddValue(element, "dc", "description", item.Overview, NS_DC);
                }
            }
            if (filter.Contains("upnp:longDescription"))
            {
                if (!string.IsNullOrWhiteSpace(item.Overview))
                {
                    AddValue(element, "upnp", "longDescription", item.Overview, NS_UPNP);
                }
            }

            if (!string.IsNullOrEmpty(item.OfficialRating))
            {
                if (filter.Contains("dc:rating"))
                {
                    AddValue(element, "dc", "rating", item.OfficialRating, NS_DC);
                }
                if (filter.Contains("upnp:rating"))
                {
                    AddValue(element, "upnp", "rating", item.OfficialRating, NS_UPNP);
                }
            }

            AddPeople(item, element);
        }
        private void AddGeneralProperties(BaseItem item, XmlElement element, Filter filter)
        {
            AddCommonFields(item, element, filter);

            var audio = item as Audio;

            if (audio != null)
            {
                foreach (var artist in audio.Artists)
                {
                    AddValue(element, "upnp", "artist", artist, NS_UPNP);
                }

                if (!string.IsNullOrEmpty(audio.Album))
                {
                    AddValue(element, "upnp", "album", audio.Album, NS_UPNP);
                }

                if (!string.IsNullOrEmpty(audio.AlbumArtist))
                {
                    AddValue(element, "upnp", "albumArtist", audio.AlbumArtist, NS_UPNP);
                }
            }

            var album = item as MusicAlbum;

            if (album != null)
            {
                if (!string.IsNullOrEmpty(album.AlbumArtist))
                {
                    AddValue(element, "upnp", "artist", album.AlbumArtist, NS_UPNP);
                    AddValue(element, "upnp", "albumArtist", album.AlbumArtist, NS_UPNP);
                }
            }

            var musicVideo = item as MusicVideo;

            if (musicVideo != null)
            {
                if (!string.IsNullOrEmpty(musicVideo.Artist))
                {
                    AddValue(element, "upnp", "artist", musicVideo.Artist, NS_UPNP);
                }

                if (!string.IsNullOrEmpty(musicVideo.Album))
                {
                    AddValue(element, "upnp", "album", musicVideo.Album, NS_UPNP);
                }
            }

            if (item.IndexNumber.HasValue)
            {
                AddValue(element, "upnp", "originalTrackNumber", item.IndexNumber.Value.ToString(_usCulture), NS_UPNP);
            }
        }
        private void AddAudioResource(XmlElement container, Audio audio, string deviceId, Filter filter)
        {
            var res = container.OwnerDocument.CreateElement(string.Empty, "res", NS_DIDL);

            var sources = _dtoService.GetMediaSources(audio);

            var streamInfo = new StreamBuilder().BuildAudioItem(new AudioOptions
            {
                ItemId = audio.Id.ToString("N"),
                MediaSources = sources,
                Profile = _profile,
                DeviceId = deviceId
            });

            var url = streamInfo.ToDlnaUrl(_serverAddress);
            res.InnerText = url;

            var mediaSource = sources.First(i => string.Equals(i.Id, streamInfo.MediaSourceId));

            if (mediaSource.RunTimeTicks.HasValue)
            {
                res.SetAttribute("duration", TimeSpan.FromTicks(mediaSource.RunTimeTicks.Value).ToString("c", _usCulture));
            }

            if (filter.Contains("res@size"))
            {
                if (streamInfo.IsDirectStream || streamInfo.EstimateContentLength)
                {
                    var size = streamInfo.TargetSize;

                    if (size.HasValue)
                    {
                        res.SetAttribute("size", size.Value.ToString(_usCulture));
                    }
                }
            }

            var targetAudioBitrate = streamInfo.TargetAudioBitrate;
            var targetSampleRate = streamInfo.TargetAudioSampleRate;
            var targetChannels = streamInfo.TargetAudioChannels;

            if (targetChannels.HasValue)
            {
                res.SetAttribute("nrAudioChannels", targetChannels.Value.ToString(_usCulture));
            }

            if (targetSampleRate.HasValue)
            {
                res.SetAttribute("sampleFrequency", targetSampleRate.Value.ToString(_usCulture));
            }

            if (targetAudioBitrate.HasValue)
            {
                res.SetAttribute("bitrate", targetAudioBitrate.Value.ToString(_usCulture));
            }

            var formatProfile = new MediaFormatProfileResolver().ResolveAudioFormat(streamInfo.Container, targetAudioBitrate, targetSampleRate, targetChannels);

            var filename = url.Substring(0, url.IndexOf('?'));

            var orgOpValue = DlnaMaps.GetOrgOpValue(mediaSource.RunTimeTicks.HasValue, streamInfo.IsDirectStream, streamInfo.TranscodeSeekInfo);

            var orgCi = streamInfo.IsDirectStream ? ";DLNA.ORG_CI=0" : ";DLNA.ORG_CI=1";

            res.SetAttribute("protocolInfo", String.Format(
                "http-get:*:{0}:DLNA.ORG_PN={1};DLNA.ORG_OP={2};DLNA.ORG_CI={3};DLNA.ORG_FLAGS={4}",
                MimeTypes.GetMimeType(filename),
                formatProfile,
                orgOpValue,
                orgCi,
                DlnaMaps.DefaultStreaming
                ));

            container.AppendChild(res);
        }
        private void AddVideoResource(XmlElement container, Video video, string deviceId, Filter filter)
        {
            var res = container.OwnerDocument.CreateElement(string.Empty, "res", NS_DIDL);

            var sources = _dtoService.GetMediaSources(video);

            int? maxBitrateSetting = null;

            var streamInfo = new StreamBuilder().BuildVideoItem(new VideoOptions
            {
                ItemId = video.Id.ToString("N"),
                MediaSources = sources,
                Profile = _profile,
                DeviceId = deviceId,
                MaxBitrate = maxBitrateSetting
            });

            var url = streamInfo.ToDlnaUrl(_serverAddress);
            res.InnerText = url;

            var mediaSource = sources.First(i => string.Equals(i.Id, streamInfo.MediaSourceId));

            if (mediaSource.RunTimeTicks.HasValue)
            {
                res.SetAttribute("duration", TimeSpan.FromTicks(mediaSource.RunTimeTicks.Value).ToString("c", _usCulture));
            }

            if (filter.Contains("res@size"))
            {
                if (streamInfo.IsDirectStream || streamInfo.EstimateContentLength)
                {
                    var size = streamInfo.TargetSize;

                    if (size.HasValue)
                    {
                        res.SetAttribute("size", size.Value.ToString(_usCulture));
                    }
                }
            }

            var videoStream = mediaSource.MediaStreams.FirstOrDefault(i => i.Type == MediaStreamType.Video && !string.Equals(i.Codec, "mjpeg", StringComparison.OrdinalIgnoreCase));

            var targetAudioBitrate = streamInfo.TargetAudioBitrate;
            var targetSampleRate = streamInfo.TargetAudioSampleRate;
            var targetChannels = streamInfo.TargetAudioChannels;

            var targetWidth = streamInfo.MaxWidth ?? (videoStream == null ? null : videoStream.Width);
            var targetHeight = streamInfo.MaxHeight ?? (videoStream == null ? null : videoStream.Height);

            var targetVideoCodec = streamInfo.IsDirectStream
                ? (videoStream == null ? null : videoStream.Codec)
                : streamInfo.VideoCodec;

            var targetAudioCodec = streamInfo.TargetAudioCodec;

            var targetBitrate = maxBitrateSetting ?? mediaSource.Bitrate;

            if (targetChannels.HasValue)
            {
                res.SetAttribute("nrAudioChannels", targetChannels.Value.ToString(_usCulture));
            }

            if (filter.Contains("res@resolution"))
            {
                if (targetWidth.HasValue && targetHeight.HasValue)
                {
                    res.SetAttribute("resolution", string.Format("{0}x{1}", targetWidth.Value, targetHeight.Value));
                }
            }

            if (targetSampleRate.HasValue)
            {
                res.SetAttribute("sampleFrequency", targetSampleRate.Value.ToString(_usCulture));
            }

            if (targetAudioBitrate.HasValue)
            {
                res.SetAttribute("bitrate", targetAudioBitrate.Value.ToString(_usCulture));
            }

            var formatProfile = new MediaFormatProfileResolver().ResolveVideoFormat(streamInfo.Container,
                targetVideoCodec,
                targetAudioCodec,
                targetWidth,
                targetHeight,
                targetBitrate,
                TransportStreamTimestamp.NONE);

            var filename = url.Substring(0, url.IndexOf('?'));

            var orgOpValue = DlnaMaps.GetOrgOpValue(mediaSource.RunTimeTicks.HasValue, streamInfo.IsDirectStream, streamInfo.TranscodeSeekInfo);

            var orgCi = streamInfo.IsDirectStream ? ";DLNA.ORG_CI=0" : ";DLNA.ORG_CI=1";

            res.SetAttribute("protocolInfo", String.Format(
                "http-get:*:{0}:DLNA.ORG_PN={1};DLNA.ORG_OP={2};DLNA.ORG_CI={3};DLNA.ORG_FLAGS={4}",
                MimeTypes.GetMimeType(filename),
                formatProfile,
                orgOpValue,
                orgCi,
                DlnaMaps.DefaultStreaming
                ));

            container.AppendChild(res);
        }
        private void Browse_AddItem(XmlDocument result, BaseItem item, User user, string deviceId, Filter filter)
        {
            var element = result.CreateElement(string.Empty, "item", NS_DIDL);
            element.SetAttribute("restricted", "1");
            element.SetAttribute("id", item.Id.ToString("N"));

            if (item.Parent != null)
            {
                element.SetAttribute("parentID", item.Parent.Id.ToString("N"));
            }

            element.AppendChild(CreateObjectClass(result, item));

            AddBookmarkInfo(item, user, element);

            AddGeneralProperties(item, element, filter);

            // refID?
            // storeAttribute(itemNode, object, ClassProperties.REF_ID, false);

            var audio = item as Audio;
            if (audio != null)
            {
                AddAudioResource(element, audio, deviceId, filter);
            }

            var video = item as Video;
            if (video != null)
            {
                AddVideoResource(element, video, deviceId, filter);
            }

            AddCover(item, element);

            result.DocumentElement.AppendChild(element);
        }
        private void Browse_AddFolder(XmlDocument result, Folder f, int childCount, Filter filter)
        {
            var container = result.CreateElement(string.Empty, "container", NS_DIDL);
            container.SetAttribute("restricted", "0");
            container.SetAttribute("searchable", "1");
            container.SetAttribute("childCount", childCount.ToString(_usCulture));
            container.SetAttribute("id", f.Id.ToString("N"));

            var parent = f.Parent;
            if (parent == null)
            {
                container.SetAttribute("parentID", "0");
            }
            else
            {
                container.SetAttribute("parentID", parent.Id.ToString("N"));
            }

            AddCommonFields(f, container, filter);

            AddCover(f, container);

            container.AppendChild(CreateObjectClass(result, f));
            result.DocumentElement.AppendChild(container);
        }
        private IEnumerable<KeyValuePair<string, string>> HandleSearch(Headers sparams, User user, string deviceId)
        {
            var searchCriteria = new SearchCriteria(sparams.GetValueOrDefault("SearchCriteria", ""));
            var sortCriteria = new SortCriteria(sparams.GetValueOrDefault("SortCriteria", ""));
            var filter = new Filter(sparams.GetValueOrDefault("Filter", "*"));

            // sort example: dc:title, dc:date

            var provided = 0;
            var requested = 0;
            var start = 0;

            if (sparams.ContainsKey("RequestedCount") && int.TryParse(sparams["RequestedCount"], out requested) && requested <= 0)
            {
                requested = 0;
            }
            if (sparams.ContainsKey("StartingIndex") && int.TryParse(sparams["StartingIndex"], out start) && start <= 0)
            {
                start = 0;
            }

            //var root = GetItem(id) as IMediaFolder;
            var result = new XmlDocument();

            var didl = result.CreateElement(string.Empty, "DIDL-Lite", NS_DIDL);
            didl.SetAttribute("xmlns:dc", NS_DC);
            didl.SetAttribute("xmlns:dlna", NS_DLNA);
            didl.SetAttribute("xmlns:upnp", NS_UPNP);
            didl.SetAttribute("xmlns:sec", NS_SEC);
            result.AppendChild(didl);

            var folder = (Folder)GetItemFromObjectId(sparams["ContainerID"], user);

            var children = GetChildrenSorted(folder, user, searchCriteria, sortCriteria).ToList();

            var totalCount = children.Count;

            if (start > 0)
            {
                children = children.Skip(start).ToList();
            }
            if (requested > 0)
            {
                children = children.Take(requested).ToList();
            }

            provided = children.Count;

            foreach (var i in children)
            {
                if (i.IsFolder)
                {
                    var f = (Folder)i;
                    var childCount = GetChildrenSorted(f, user, searchCriteria, sortCriteria).Count();

                    Browse_AddFolder(result, f, childCount, filter);
                }
                else
                {
                    Browse_AddItem(result, i, user, deviceId, filter);
                }
            }

            var resXML = result.OuterXml;

            return new List<KeyValuePair<string, string>>
            {
                new KeyValuePair<string,string>("Result", resXML),
                new KeyValuePair<string,string>("NumberReturned", provided.ToString(_usCulture)),
                new KeyValuePair<string,string>("TotalMatches", totalCount.ToString(_usCulture)),
                new KeyValuePair<string,string>("UpdateID", _systemUpdateId.ToString(_usCulture))
            };
        }