|  | @@ -1,5 +1,4 @@
 | 
	
		
			
				|  |  |  #pragma warning disable CS1591
 | 
	
		
			
				|  |  | -#pragma warning disable SA1600
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  using System;
 | 
	
		
			
				|  |  |  using System.Globalization;
 | 
	
	
		
			
				|  | @@ -46,6 +45,7 @@ namespace Emby.Dlna.Didl
 | 
	
		
			
				|  |  |          private readonly IMediaSourceManager _mediaSourceManager;
 | 
	
		
			
				|  |  |          private readonly ILogger _logger;
 | 
	
		
			
				|  |  |          private readonly IMediaEncoder _mediaEncoder;
 | 
	
		
			
				|  |  | +        private readonly ILibraryManager _libraryManager;
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |          public DidlBuilder(
 | 
	
		
			
				|  |  |              DeviceProfile profile,
 | 
	
	
		
			
				|  | @@ -57,7 +57,8 @@ namespace Emby.Dlna.Didl
 | 
	
		
			
				|  |  |              ILocalizationManager localization,
 | 
	
		
			
				|  |  |              IMediaSourceManager mediaSourceManager,
 | 
	
		
			
				|  |  |              ILogger logger,
 | 
	
		
			
				|  |  | -            IMediaEncoder mediaEncoder)
 | 
	
		
			
				|  |  | +            IMediaEncoder mediaEncoder,
 | 
	
		
			
				|  |  | +            ILibraryManager libraryManager)
 | 
	
		
			
				|  |  |          {
 | 
	
		
			
				|  |  |              _profile = profile;
 | 
	
		
			
				|  |  |              _user = user;
 | 
	
	
		
			
				|  | @@ -69,6 +70,7 @@ namespace Emby.Dlna.Didl
 | 
	
		
			
				|  |  |              _mediaSourceManager = mediaSourceManager;
 | 
	
		
			
				|  |  |              _logger = logger;
 | 
	
		
			
				|  |  |              _mediaEncoder = mediaEncoder;
 | 
	
		
			
				|  |  | +            _libraryManager = libraryManager;
 | 
	
		
			
				|  |  |          }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |          public static string NormalizeDlnaMediaUrl(string url)
 | 
	
	
		
			
				|  | @@ -76,7 +78,7 @@ namespace Emby.Dlna.Didl
 | 
	
		
			
				|  |  |              return url + "&dlnaheaders=true";
 | 
	
		
			
				|  |  |          }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -        public string GetItemDidl(DlnaOptions options, BaseItem item, User user, BaseItem context, string deviceId, Filter filter, StreamInfo streamInfo)
 | 
	
		
			
				|  |  | +        public string GetItemDidl(BaseItem item, User user, BaseItem context, string deviceId, Filter filter, StreamInfo streamInfo)
 | 
	
		
			
				|  |  |          {
 | 
	
		
			
				|  |  |              var settings = new XmlWriterSettings
 | 
	
		
			
				|  |  |              {
 | 
	
	
		
			
				|  | @@ -101,7 +103,7 @@ namespace Emby.Dlna.Didl
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |                      WriteXmlRootAttributes(_profile, writer);
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -                    WriteItemElement(options, writer, item, user, context, null, deviceId, filter, streamInfo);
 | 
	
		
			
				|  |  | +                    WriteItemElement(writer, item, user, context, null, deviceId, filter, streamInfo);
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |                      writer.WriteFullEndElement();
 | 
	
		
			
				|  |  |                      //writer.WriteEndDocument();
 | 
	
	
		
			
				|  | @@ -128,7 +130,6 @@ namespace Emby.Dlna.Didl
 | 
	
		
			
				|  |  |          }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |          public void WriteItemElement(
 | 
	
		
			
				|  |  | -            DlnaOptions options,
 | 
	
		
			
				|  |  |              XmlWriter writer,
 | 
	
		
			
				|  |  |              BaseItem item,
 | 
	
		
			
				|  |  |              User user,
 | 
	
	
		
			
				|  | @@ -165,25 +166,23 @@ namespace Emby.Dlna.Didl
 | 
	
		
			
				|  |  |              // refID?
 | 
	
		
			
				|  |  |              // storeAttribute(itemNode, object, ClassProperties.REF_ID, false);
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -            var hasMediaSources = item as IHasMediaSources;
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -            if (hasMediaSources != null)
 | 
	
		
			
				|  |  | +            if (item is IHasMediaSources)
 | 
	
		
			
				|  |  |              {
 | 
	
		
			
				|  |  |                  if (string.Equals(item.MediaType, MediaType.Audio, StringComparison.OrdinalIgnoreCase))
 | 
	
		
			
				|  |  |                  {
 | 
	
		
			
				|  |  | -                    AddAudioResource(options, writer, item, deviceId, filter, streamInfo);
 | 
	
		
			
				|  |  | +                    AddAudioResource(writer, item, deviceId, filter, streamInfo);
 | 
	
		
			
				|  |  |                  }
 | 
	
		
			
				|  |  |                  else if (string.Equals(item.MediaType, MediaType.Video, StringComparison.OrdinalIgnoreCase))
 | 
	
		
			
				|  |  |                  {
 | 
	
		
			
				|  |  | -                    AddVideoResource(options, writer, item, deviceId, filter, streamInfo);
 | 
	
		
			
				|  |  | +                    AddVideoResource(writer, item, deviceId, filter, streamInfo);
 | 
	
		
			
				|  |  |                  }
 | 
	
		
			
				|  |  |              }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -            AddCover(item, context, null, writer);
 | 
	
		
			
				|  |  | +            AddCover(item, null, writer);
 | 
	
		
			
				|  |  |              writer.WriteFullEndElement();
 | 
	
		
			
				|  |  |          }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -        private void AddVideoResource(DlnaOptions options, XmlWriter writer, BaseItem video, string deviceId, Filter filter, StreamInfo streamInfo = null)
 | 
	
		
			
				|  |  | +        private void AddVideoResource(XmlWriter writer, BaseItem video, string deviceId, Filter filter, StreamInfo streamInfo = null)
 | 
	
		
			
				|  |  |          {
 | 
	
		
			
				|  |  |              if (streamInfo == null)
 | 
	
		
			
				|  |  |              {
 | 
	
	
		
			
				|  | @@ -227,7 +226,7 @@ namespace Emby.Dlna.Didl
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |              foreach (var contentFeature in contentFeatureList)
 | 
	
		
			
				|  |  |              {
 | 
	
		
			
				|  |  | -                AddVideoResource(writer, video, deviceId, filter, contentFeature, streamInfo);
 | 
	
		
			
				|  |  | +                AddVideoResource(writer, filter, contentFeature, streamInfo);
 | 
	
		
			
				|  |  |              }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |              var subtitleProfiles = streamInfo.GetSubtitleProfiles(_mediaEncoder, false, _serverAddress, _accessToken);
 | 
	
	
		
			
				|  | @@ -284,7 +283,10 @@ namespace Emby.Dlna.Didl
 | 
	
		
			
				|  |  |              else
 | 
	
		
			
				|  |  |              {
 | 
	
		
			
				|  |  |                  writer.WriteStartElement(string.Empty, "res", NS_DIDL);
 | 
	
		
			
				|  |  | -                var protocolInfo = string.Format("http-get:*:text/{0}:*", info.Format.ToLowerInvariant());
 | 
	
		
			
				|  |  | +                var protocolInfo = string.Format(
 | 
	
		
			
				|  |  | +                    CultureInfo.InvariantCulture,
 | 
	
		
			
				|  |  | +                    "http-get:*:text/{0}:*",
 | 
	
		
			
				|  |  | +                    info.Format.ToLowerInvariant());
 | 
	
		
			
				|  |  |                  writer.WriteAttributeString("protocolInfo", protocolInfo);
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |                  writer.WriteString(info.Url);
 | 
	
	
		
			
				|  | @@ -294,7 +296,7 @@ namespace Emby.Dlna.Didl
 | 
	
		
			
				|  |  |              return true;
 | 
	
		
			
				|  |  |          }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -        private void AddVideoResource(XmlWriter writer, BaseItem video, string deviceId, Filter filter, string contentFeatures, StreamInfo streamInfo)
 | 
	
		
			
				|  |  | +        private void AddVideoResource(XmlWriter writer, Filter filter, string contentFeatures, StreamInfo streamInfo)
 | 
	
		
			
				|  |  |          {
 | 
	
		
			
				|  |  |              writer.WriteStartElement(string.Empty, "res", NS_DIDL);
 | 
	
		
			
				|  |  |  
 | 
	
	
		
			
				|  | @@ -336,7 +338,13 @@ namespace Emby.Dlna.Didl
 | 
	
		
			
				|  |  |              {
 | 
	
		
			
				|  |  |                  if (targetWidth.HasValue && targetHeight.HasValue)
 | 
	
		
			
				|  |  |                  {
 | 
	
		
			
				|  |  | -                    writer.WriteAttributeString("resolution", string.Format("{0}x{1}", targetWidth.Value, targetHeight.Value));
 | 
	
		
			
				|  |  | +                    writer.WriteAttributeString(
 | 
	
		
			
				|  |  | +                        "resolution",
 | 
	
		
			
				|  |  | +                        string.Format(
 | 
	
		
			
				|  |  | +                            CultureInfo.InvariantCulture,
 | 
	
		
			
				|  |  | +                            "{0}x{1}",
 | 
	
		
			
				|  |  | +                            targetWidth.Value,
 | 
	
		
			
				|  |  | +                            targetHeight.Value));
 | 
	
		
			
				|  |  |                  }
 | 
	
		
			
				|  |  |              }
 | 
	
		
			
				|  |  |  
 | 
	
	
		
			
				|  | @@ -370,17 +378,19 @@ namespace Emby.Dlna.Didl
 | 
	
		
			
				|  |  |                  streamInfo.TargetVideoCodecTag,
 | 
	
		
			
				|  |  |                  streamInfo.IsTargetAVC);
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -            var filename = url.Substring(0, url.IndexOf('?'));
 | 
	
		
			
				|  |  | +            var filename = url.Substring(0, url.IndexOf('?', StringComparison.Ordinal));
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |              var mimeType = mediaProfile == null || string.IsNullOrEmpty(mediaProfile.MimeType)
 | 
	
		
			
				|  |  |                 ? MimeTypes.GetMimeType(filename)
 | 
	
		
			
				|  |  |                 : mediaProfile.MimeType;
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -            writer.WriteAttributeString("protocolInfo", string.Format(
 | 
	
		
			
				|  |  | -                "http-get:*:{0}:{1}",
 | 
	
		
			
				|  |  | -                mimeType,
 | 
	
		
			
				|  |  | -                contentFeatures
 | 
	
		
			
				|  |  | -                ));
 | 
	
		
			
				|  |  | +            writer.WriteAttributeString(
 | 
	
		
			
				|  |  | +                "protocolInfo",
 | 
	
		
			
				|  |  | +                string.Format(
 | 
	
		
			
				|  |  | +                    CultureInfo.InvariantCulture,
 | 
	
		
			
				|  |  | +                    "http-get:*:{0}:{1}",
 | 
	
		
			
				|  |  | +                    mimeType,
 | 
	
		
			
				|  |  | +                    contentFeatures));
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |              writer.WriteString(url);
 | 
	
		
			
				|  |  |  
 | 
	
	
		
			
				|  | @@ -393,24 +403,24 @@ namespace Emby.Dlna.Didl
 | 
	
		
			
				|  |  |              {
 | 
	
		
			
				|  |  |                  switch (itemStubType.Value)
 | 
	
		
			
				|  |  |                  {
 | 
	
		
			
				|  |  | -                    case StubType.Latest:           return _localization.GetLocalizedString("Latest");
 | 
	
		
			
				|  |  | -                    case StubType.Playlists:        return _localization.GetLocalizedString("Playlists");
 | 
	
		
			
				|  |  | -                    case StubType.AlbumArtists:     return _localization.GetLocalizedString("HeaderAlbumArtists");
 | 
	
		
			
				|  |  | -                    case StubType.Albums:           return _localization.GetLocalizedString("Albums");
 | 
	
		
			
				|  |  | -                    case StubType.Artists:          return _localization.GetLocalizedString("Artists");
 | 
	
		
			
				|  |  | -                    case StubType.Songs:            return _localization.GetLocalizedString("Songs");
 | 
	
		
			
				|  |  | -                    case StubType.Genres:           return _localization.GetLocalizedString("Genres");
 | 
	
		
			
				|  |  | -                    case StubType.FavoriteAlbums:   return _localization.GetLocalizedString("HeaderFavoriteAlbums");
 | 
	
		
			
				|  |  | -                    case StubType.FavoriteArtists:  return _localization.GetLocalizedString("HeaderFavoriteArtists");
 | 
	
		
			
				|  |  | -                    case StubType.FavoriteSongs:    return _localization.GetLocalizedString("HeaderFavoriteSongs");
 | 
	
		
			
				|  |  | +                    case StubType.Latest: return _localization.GetLocalizedString("Latest");
 | 
	
		
			
				|  |  | +                    case StubType.Playlists: return _localization.GetLocalizedString("Playlists");
 | 
	
		
			
				|  |  | +                    case StubType.AlbumArtists: return _localization.GetLocalizedString("HeaderAlbumArtists");
 | 
	
		
			
				|  |  | +                    case StubType.Albums: return _localization.GetLocalizedString("Albums");
 | 
	
		
			
				|  |  | +                    case StubType.Artists: return _localization.GetLocalizedString("Artists");
 | 
	
		
			
				|  |  | +                    case StubType.Songs: return _localization.GetLocalizedString("Songs");
 | 
	
		
			
				|  |  | +                    case StubType.Genres: return _localization.GetLocalizedString("Genres");
 | 
	
		
			
				|  |  | +                    case StubType.FavoriteAlbums: return _localization.GetLocalizedString("HeaderFavoriteAlbums");
 | 
	
		
			
				|  |  | +                    case StubType.FavoriteArtists: return _localization.GetLocalizedString("HeaderFavoriteArtists");
 | 
	
		
			
				|  |  | +                    case StubType.FavoriteSongs: return _localization.GetLocalizedString("HeaderFavoriteSongs");
 | 
	
		
			
				|  |  |                      case StubType.ContinueWatching: return _localization.GetLocalizedString("HeaderContinueWatching");
 | 
	
		
			
				|  |  | -                    case StubType.Movies:           return _localization.GetLocalizedString("Movies");
 | 
	
		
			
				|  |  | -                    case StubType.Collections:      return _localization.GetLocalizedString("Collections");
 | 
	
		
			
				|  |  | -                    case StubType.Favorites:        return _localization.GetLocalizedString("Favorites");
 | 
	
		
			
				|  |  | -                    case StubType.NextUp:           return _localization.GetLocalizedString("HeaderNextUp");
 | 
	
		
			
				|  |  | -                    case StubType.FavoriteSeries:   return _localization.GetLocalizedString("HeaderFavoriteShows");
 | 
	
		
			
				|  |  | +                    case StubType.Movies: return _localization.GetLocalizedString("Movies");
 | 
	
		
			
				|  |  | +                    case StubType.Collections: return _localization.GetLocalizedString("Collections");
 | 
	
		
			
				|  |  | +                    case StubType.Favorites: return _localization.GetLocalizedString("Favorites");
 | 
	
		
			
				|  |  | +                    case StubType.NextUp: return _localization.GetLocalizedString("HeaderNextUp");
 | 
	
		
			
				|  |  | +                    case StubType.FavoriteSeries: return _localization.GetLocalizedString("HeaderFavoriteShows");
 | 
	
		
			
				|  |  |                      case StubType.FavoriteEpisodes: return _localization.GetLocalizedString("HeaderFavoriteEpisodes");
 | 
	
		
			
				|  |  | -                    case StubType.Series:           return _localization.GetLocalizedString("Shows");
 | 
	
		
			
				|  |  | +                    case StubType.Series: return _localization.GetLocalizedString("Shows");
 | 
	
		
			
				|  |  |                      default: break;
 | 
	
		
			
				|  |  |                  }
 | 
	
		
			
				|  |  |              }
 | 
	
	
		
			
				|  | @@ -421,7 +431,10 @@ namespace Emby.Dlna.Didl
 | 
	
		
			
				|  |  |                  if (item.ParentIndexNumber.HasValue && item.ParentIndexNumber.Value == 0
 | 
	
		
			
				|  |  |                      && season.IndexNumber.HasValue && season.IndexNumber.Value != 0)
 | 
	
		
			
				|  |  |                  {
 | 
	
		
			
				|  |  | -                    return string.Format(_localization.GetLocalizedString("ValueSpecialEpisodeName"), item.Name);
 | 
	
		
			
				|  |  | +                    return string.Format(
 | 
	
		
			
				|  |  | +                        CultureInfo.InvariantCulture,
 | 
	
		
			
				|  |  | +                        _localization.GetLocalizedString("ValueSpecialEpisodeName"),
 | 
	
		
			
				|  |  | +                        item.Name);
 | 
	
		
			
				|  |  |                  }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |                  if (item.IndexNumber.HasValue)
 | 
	
	
		
			
				|  | @@ -436,11 +449,34 @@ namespace Emby.Dlna.Didl
 | 
	
		
			
				|  |  |                      return number + " - " + item.Name;
 | 
	
		
			
				|  |  |                  }
 | 
	
		
			
				|  |  |              }
 | 
	
		
			
				|  |  | +            else if (item is Episode ep)
 | 
	
		
			
				|  |  | +            {
 | 
	
		
			
				|  |  | +                var parent = ep.GetParent();
 | 
	
		
			
				|  |  | +                var name = parent.Name + " - ";
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +                if (ep.ParentIndexNumber.HasValue)
 | 
	
		
			
				|  |  | +                {
 | 
	
		
			
				|  |  | +                    name += "S" + ep.ParentIndexNumber.Value.ToString("00", CultureInfo.InvariantCulture);
 | 
	
		
			
				|  |  | +                }
 | 
	
		
			
				|  |  | +                else if (!item.IndexNumber.HasValue)
 | 
	
		
			
				|  |  | +                {
 | 
	
		
			
				|  |  | +                    return name + " - " + item.Name;
 | 
	
		
			
				|  |  | +                }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +                name += "E" + ep.IndexNumber.Value.ToString("00", CultureInfo.InvariantCulture);
 | 
	
		
			
				|  |  | +                if (ep.IndexNumberEnd.HasValue)
 | 
	
		
			
				|  |  | +                {
 | 
	
		
			
				|  |  | +                    name += "-" + ep.IndexNumberEnd.Value.ToString("00", CultureInfo.InvariantCulture);
 | 
	
		
			
				|  |  | +                }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +                name += " - " + item.Name;
 | 
	
		
			
				|  |  | +                return name;
 | 
	
		
			
				|  |  | +            }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |              return item.Name;
 | 
	
		
			
				|  |  |          }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -        private void AddAudioResource(DlnaOptions options, XmlWriter writer, BaseItem audio, string deviceId, Filter filter, StreamInfo streamInfo = null)
 | 
	
		
			
				|  |  | +        private void AddAudioResource(XmlWriter writer, BaseItem audio, string deviceId, Filter filter, StreamInfo streamInfo = null)
 | 
	
		
			
				|  |  |          {
 | 
	
		
			
				|  |  |              writer.WriteStartElement(string.Empty, "res", NS_DIDL);
 | 
	
		
			
				|  |  |  
 | 
	
	
		
			
				|  | @@ -506,7 +542,7 @@ namespace Emby.Dlna.Didl
 | 
	
		
			
				|  |  |                  targetSampleRate,
 | 
	
		
			
				|  |  |                  targetAudioBitDepth);
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -            var filename = url.Substring(0, url.IndexOf('?'));
 | 
	
		
			
				|  |  | +            var filename = url.Substring(0, url.IndexOf('?', StringComparison.Ordinal));
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |              var mimeType = mediaProfile == null || string.IsNullOrEmpty(mediaProfile.MimeType)
 | 
	
		
			
				|  |  |                  ? MimeTypes.GetMimeType(filename)
 | 
	
	
		
			
				|  | @@ -522,11 +558,13 @@ namespace Emby.Dlna.Didl
 | 
	
		
			
				|  |  |                  streamInfo.RunTimeTicks ?? 0,
 | 
	
		
			
				|  |  |                  streamInfo.TranscodeSeekInfo);
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -            writer.WriteAttributeString("protocolInfo", string.Format(
 | 
	
		
			
				|  |  | -                "http-get:*:{0}:{1}",
 | 
	
		
			
				|  |  | -                mimeType,
 | 
	
		
			
				|  |  | -                contentFeatures
 | 
	
		
			
				|  |  | -                ));
 | 
	
		
			
				|  |  | +            writer.WriteAttributeString(
 | 
	
		
			
				|  |  | +                "protocolInfo",
 | 
	
		
			
				|  |  | +                string.Format(
 | 
	
		
			
				|  |  | +                    CultureInfo.InvariantCulture,
 | 
	
		
			
				|  |  | +                    "http-get:*:{0}:{1}",
 | 
	
		
			
				|  |  | +                    mimeType,
 | 
	
		
			
				|  |  | +                    contentFeatures));
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |              writer.WriteString(url);
 | 
	
		
			
				|  |  |  
 | 
	
	
		
			
				|  | @@ -549,7 +587,7 @@ namespace Emby.Dlna.Didl
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |              var clientId = GetClientId(folder, stubType);
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -            if (string.Equals(requestedId, "0"))
 | 
	
		
			
				|  |  | +            if (string.Equals(requestedId, "0", StringComparison.Ordinal))
 | 
	
		
			
				|  |  |              {
 | 
	
		
			
				|  |  |                  writer.WriteAttributeString("id", "0");
 | 
	
		
			
				|  |  |                  writer.WriteAttributeString("parentID", "-1");
 | 
	
	
		
			
				|  | @@ -578,7 +616,7 @@ namespace Emby.Dlna.Didl
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |              AddGeneralProperties(folder, stubType, context, writer, filter);
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -            AddCover(folder, context, stubType, writer);
 | 
	
		
			
				|  |  | +            AddCover(folder, stubType, writer);
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |              writer.WriteFullEndElement();
 | 
	
		
			
				|  |  |          }
 | 
	
	
		
			
				|  | @@ -611,7 +649,10 @@ namespace Emby.Dlna.Didl
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |              if (playbackPositionTicks > 0)
 | 
	
		
			
				|  |  |              {
 | 
	
		
			
				|  |  | -                var elementValue = string.Format("BM={0}", Convert.ToInt32(TimeSpan.FromTicks(playbackPositionTicks).TotalSeconds).ToString(_usCulture));
 | 
	
		
			
				|  |  | +                var elementValue = string.Format(
 | 
	
		
			
				|  |  | +                    CultureInfo.InvariantCulture,
 | 
	
		
			
				|  |  | +                    "BM={0}",
 | 
	
		
			
				|  |  | +                    Convert.ToInt32(TimeSpan.FromTicks(playbackPositionTicks).TotalSeconds));
 | 
	
		
			
				|  |  |                  AddValue(writer, "sec", "dcmInfo", elementValue, secAttribute.Value);
 | 
	
		
			
				|  |  |              }
 | 
	
		
			
				|  |  |          }
 | 
	
	
		
			
				|  | @@ -764,37 +805,36 @@ namespace Emby.Dlna.Didl
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |          private void AddPeople(BaseItem item, XmlWriter writer)
 | 
	
		
			
				|  |  |          {
 | 
	
		
			
				|  |  | -            //var types = new[]
 | 
	
		
			
				|  |  | -            //{
 | 
	
		
			
				|  |  | -            //    PersonType.Director,
 | 
	
		
			
				|  |  | -            //    PersonType.Writer,
 | 
	
		
			
				|  |  | -            //    PersonType.Producer,
 | 
	
		
			
				|  |  | -            //    PersonType.Composer,
 | 
	
		
			
				|  |  | -            //    "Creator"
 | 
	
		
			
				|  |  | -            //};
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -            //var people = _libraryManager.GetPeople(item);
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -            //var index = 0;
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -            //// Seeing some LG models locking up due content with large lists of people
 | 
	
		
			
				|  |  | -            //// The actual issue might just be due to processing a more metadata than it can handle
 | 
	
		
			
				|  |  | -            //var limit = 6;
 | 
	
		
			
				|  |  | +            if (!item.SupportsPeople)
 | 
	
		
			
				|  |  | +            {
 | 
	
		
			
				|  |  | +                return;
 | 
	
		
			
				|  |  | +            }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -            //foreach (var actor in people)
 | 
	
		
			
				|  |  | -            //{
 | 
	
		
			
				|  |  | -            //    var type = types.FirstOrDefault(i => string.Equals(i, actor.Type, StringComparison.OrdinalIgnoreCase) || string.Equals(i, actor.Role, StringComparison.OrdinalIgnoreCase))
 | 
	
		
			
				|  |  | -            //        ?? PersonType.Actor;
 | 
	
		
			
				|  |  | +            var types = new[]
 | 
	
		
			
				|  |  | +            {
 | 
	
		
			
				|  |  | +                PersonType.Director,
 | 
	
		
			
				|  |  | +                PersonType.Writer,
 | 
	
		
			
				|  |  | +                PersonType.Producer,
 | 
	
		
			
				|  |  | +                PersonType.Composer,
 | 
	
		
			
				|  |  | +                "creator"
 | 
	
		
			
				|  |  | +            };
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -            //    AddValue(writer, "upnp", type.ToLowerInvariant(), actor.Name, NS_UPNP);
 | 
	
		
			
				|  |  | +            // Seeing some LG models locking up due content with large lists of people
 | 
	
		
			
				|  |  | +            // The actual issue might just be due to processing a more metadata than it can handle
 | 
	
		
			
				|  |  | +            var people = _libraryManager.GetPeople(
 | 
	
		
			
				|  |  | +                new InternalPeopleQuery
 | 
	
		
			
				|  |  | +                {
 | 
	
		
			
				|  |  | +                    ItemId = item.Id,
 | 
	
		
			
				|  |  | +                    Limit = 6
 | 
	
		
			
				|  |  | +                });
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -            //    index++;
 | 
	
		
			
				|  |  | +            foreach (var actor in people)
 | 
	
		
			
				|  |  | +            {
 | 
	
		
			
				|  |  | +                var type = types.FirstOrDefault(i => string.Equals(i, actor.Type, StringComparison.OrdinalIgnoreCase) || string.Equals(i, actor.Role, StringComparison.OrdinalIgnoreCase))
 | 
	
		
			
				|  |  | +                    ?? PersonType.Actor;
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -            //    if (index >= limit)
 | 
	
		
			
				|  |  | -            //    {
 | 
	
		
			
				|  |  | -            //        break;
 | 
	
		
			
				|  |  | -            //    }
 | 
	
		
			
				|  |  | -            //}
 | 
	
		
			
				|  |  | +                AddValue(writer, "upnp", type.ToLowerInvariant(), actor.Name, NS_UPNP);
 | 
	
		
			
				|  |  | +            }
 | 
	
		
			
				|  |  |          }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |          private void AddGeneralProperties(BaseItem item, StubType? itemStubType, BaseItem context, XmlWriter writer, Filter filter)
 | 
	
	
		
			
				|  | @@ -871,7 +911,7 @@ namespace Emby.Dlna.Didl
 | 
	
		
			
				|  |  |              }
 | 
	
		
			
				|  |  |          }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -        private void AddCover(BaseItem item, BaseItem context, StubType? stubType, XmlWriter writer)
 | 
	
		
			
				|  |  | +        private void AddCover(BaseItem item, StubType? stubType, XmlWriter writer)
 | 
	
		
			
				|  |  |          {
 | 
	
		
			
				|  |  |              ImageDownloadInfo imageInfo = GetImageInfo(item);
 | 
	
		
			
				|  |  |  
 | 
	
	
		
			
				|  | @@ -916,17 +956,8 @@ namespace Emby.Dlna.Didl
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |          }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -        private void AddEmbeddedImageAsCover(string name, XmlWriter writer)
 | 
	
		
			
				|  |  | -        {
 | 
	
		
			
				|  |  | -            writer.WriteStartElement("upnp", "albumArtURI", NS_UPNP);
 | 
	
		
			
				|  |  | -            writer.WriteAttributeString("dlna", "profileID", NS_DLNA, _profile.AlbumArtPn);
 | 
	
		
			
				|  |  | -            writer.WriteString(_serverAddress + "/Dlna/icons/people480.jpg");
 | 
	
		
			
				|  |  | -            writer.WriteFullEndElement();
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -            writer.WriteElementString("upnp", "icon", NS_UPNP, _serverAddress + "/Dlna/icons/people48.jpg");
 | 
	
		
			
				|  |  | -        }
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -        private void AddImageResElement(BaseItem item,
 | 
	
		
			
				|  |  | +        private void AddImageResElement(
 | 
	
		
			
				|  |  | +            BaseItem item,
 | 
	
		
			
				|  |  |              XmlWriter writer,
 | 
	
		
			
				|  |  |              int maxWidth,
 | 
	
		
			
				|  |  |              int maxHeight,
 | 
	
	
		
			
				|  | @@ -952,13 +983,17 @@ namespace Emby.Dlna.Didl
 | 
	
		
			
				|  |  |              var contentFeatures = new ContentFeatureBuilder(_profile)
 | 
	
		
			
				|  |  |                  .BuildImageHeader(format, width, height, imageInfo.IsDirectStream, org_Pn);
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -            writer.WriteAttributeString("protocolInfo", string.Format(
 | 
	
		
			
				|  |  | -                "http-get:*:{0}:{1}",
 | 
	
		
			
				|  |  | -                MimeTypes.GetMimeType("file." + format),
 | 
	
		
			
				|  |  | -                contentFeatures
 | 
	
		
			
				|  |  | -                ));
 | 
	
		
			
				|  |  | +            writer.WriteAttributeString(
 | 
	
		
			
				|  |  | +                "protocolInfo",
 | 
	
		
			
				|  |  | +                string.Format(
 | 
	
		
			
				|  |  | +                    CultureInfo.InvariantCulture,
 | 
	
		
			
				|  |  | +                    "http-get:*:{0}:{1}",
 | 
	
		
			
				|  |  | +                    MimeTypes.GetMimeType("file." + format),
 | 
	
		
			
				|  |  | +                    contentFeatures));
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -            writer.WriteAttributeString("resolution", string.Format("{0}x{1}", width, height));
 | 
	
		
			
				|  |  | +            writer.WriteAttributeString(
 | 
	
		
			
				|  |  | +                "resolution",
 | 
	
		
			
				|  |  | +                string.Format(CultureInfo.InvariantCulture, "{0}x{1}", width, height));
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |              writer.WriteString(albumartUrlInfo.Url);
 | 
	
		
			
				|  |  |  
 | 
	
	
		
			
				|  | @@ -1097,7 +1132,9 @@ namespace Emby.Dlna.Didl
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |          private ImageUrlInfo GetImageUrl(ImageDownloadInfo info, int maxWidth, int maxHeight, string format)
 | 
	
		
			
				|  |  |          {
 | 
	
		
			
				|  |  | -            var url = string.Format("{0}/Items/{1}/Images/{2}/0/{3}/{4}/{5}/{6}/0/0",
 | 
	
		
			
				|  |  | +            var url = string.Format(
 | 
	
		
			
				|  |  | +                CultureInfo.InvariantCulture,
 | 
	
		
			
				|  |  | +                "{0}/Items/{1}/Images/{2}/0/{3}/{4}/{5}/{6}/0/0",
 | 
	
		
			
				|  |  |                  _serverAddress,
 | 
	
		
			
				|  |  |                  info.ItemId.ToString("N", CultureInfo.InvariantCulture),
 | 
	
		
			
				|  |  |                  info.Type,
 |