Browse Source

improve guide loading performance

Luke Pulverenti 9 years ago
parent
commit
edecae6ed5

+ 14 - 12
Emby.Drawing/ImageProcessor.cs

@@ -410,18 +410,20 @@ namespace Emby.Drawing
         {
             ImageSize size;
 
-            try
-            {
-                size = ImageHeader.GetDimensions(path, _logger, _fileSystem);
-            }
-            catch
-            {
-                _logger.Info("Failed to read image header for {0}. Doing it the slow way.", path);
-
-                CheckDisposed();
-
-                size = _imageEncoder.GetImageSize(path);
-            }
+            size = ImageHeader.GetDimensions(path, _logger, _fileSystem);
+            //try
+            //{
+            //    size = ImageHeader.GetDimensions(path, _logger, _fileSystem);
+            //}
+            //catch
+            //{
+            //    return;
+            //    //_logger.Info("Failed to read image header for {0}. Doing it the slow way.", path);
+
+            //    //CheckDisposed();
+
+            //    //size = _imageEncoder.GetImageSize(path);
+            //}
 
             StartSaveImageSizeTimer();
 

+ 72 - 8
MediaBrowser.Api/LiveTv/LiveTvService.cs

@@ -29,7 +29,7 @@ namespace MediaBrowser.Api.LiveTv
 
     [Route("/LiveTv/Channels", "GET", Summary = "Gets available live tv channels.")]
     [Authenticated]
-    public class GetChannels : IReturn<QueryResult<ChannelInfoDto>>
+    public class GetChannels : IReturn<QueryResult<ChannelInfoDto>>, IHasDtoOptions
     {
         [ApiMember(Name = "Type", Description = "Optional filter by channel type.", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET")]
         public ChannelType? Type { get; set; }
@@ -62,6 +62,22 @@ namespace MediaBrowser.Api.LiveTv
 
         [ApiMember(Name = "EnableFavoriteSorting", Description = "Incorporate favorite and like status into channel sorting.", IsRequired = false, DataType = "bool", ParameterType = "query", Verb = "GET")]
         public bool EnableFavoriteSorting { get; set; }
+
+        [ApiMember(Name = "EnableImages", Description = "Optional, include image information in output", IsRequired = false, DataType = "boolean", ParameterType = "query", Verb = "GET")]
+        public bool? EnableImages { get; set; }
+
+        [ApiMember(Name = "ImageTypeLimit", Description = "Optional, the max number of images to return, per image type", IsRequired = false, DataType = "int", ParameterType = "query", Verb = "GET")]
+        public int? ImageTypeLimit { get; set; }
+
+        [ApiMember(Name = "EnableImageTypes", Description = "Optional. The image types to include in the output.", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET")]
+        public string EnableImageTypes { get; set; }
+
+        /// <summary>
+        /// Fields to return within the items, in addition to basic information
+        /// </summary>
+        /// <value>The fields.</value>
+        [ApiMember(Name = "Fields", Description = "Optional. Specify additional fields of information to return in the output. This allows multiple, comma delimeted. Options: Budget, Chapters, CriticRatingSummary, DateCreated, Genres, HomePageUrl, IndexOptions, MediaStreams, Overview, ParentId, Path, People, ProviderIds, PrimaryImageAspectRatio, Revenue, SortName, Studios, Taglines", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET", AllowMultiple = true)]
+        public string Fields { get; set; }
     }
 
     [Route("/LiveTv/Channels/{Id}", "GET", Summary = "Gets a live tv channel")]
@@ -81,7 +97,7 @@ namespace MediaBrowser.Api.LiveTv
 
     [Route("/LiveTv/Recordings", "GET", Summary = "Gets live tv recordings")]
     [Authenticated]
-    public class GetRecordings : IReturn<QueryResult<BaseItemDto>>
+    public class GetRecordings : IReturn<QueryResult<BaseItemDto>>, IHasDtoOptions
     {
         [ApiMember(Name = "ChannelId", Description = "Optional filter by channel id.", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET")]
         public string ChannelId { get; set; }
@@ -106,6 +122,22 @@ namespace MediaBrowser.Api.LiveTv
 
         [ApiMember(Name = "SeriesTimerId", Description = "Optional filter by recordings belonging to a series timer", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET")]
         public string SeriesTimerId { get; set; }
+
+        [ApiMember(Name = "EnableImages", Description = "Optional, include image information in output", IsRequired = false, DataType = "boolean", ParameterType = "query", Verb = "GET")]
+        public bool? EnableImages { get; set; }
+
+        [ApiMember(Name = "ImageTypeLimit", Description = "Optional, the max number of images to return, per image type", IsRequired = false, DataType = "int", ParameterType = "query", Verb = "GET")]
+        public int? ImageTypeLimit { get; set; }
+
+        [ApiMember(Name = "EnableImageTypes", Description = "Optional. The image types to include in the output.", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET")]
+        public string EnableImageTypes { get; set; }
+
+        /// <summary>
+        /// Fields to return within the items, in addition to basic information
+        /// </summary>
+        /// <value>The fields.</value>
+        [ApiMember(Name = "Fields", Description = "Optional. Specify additional fields of information to return in the output. This allows multiple, comma delimeted. Options: Budget, Chapters, CriticRatingSummary, DateCreated, Genres, HomePageUrl, IndexOptions, MediaStreams, Overview, ParentId, Path, People, ProviderIds, PrimaryImageAspectRatio, Revenue, SortName, Studios, Taglines", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET", AllowMultiple = true)]
+        public string Fields { get; set; }
     }
 
     [Route("/LiveTv/Recordings/Groups", "GET", Summary = "Gets live tv recording groups")]
@@ -164,7 +196,7 @@ namespace MediaBrowser.Api.LiveTv
 
     [Route("/LiveTv/Programs", "GET,POST", Summary = "Gets available live tv epgs..")]
     [Authenticated]
-    public class GetPrograms : IReturn<QueryResult<BaseItemDto>>
+    public class GetPrograms : IReturn<QueryResult<BaseItemDto>>, IHasDtoOptions
     {
         [ApiMember(Name = "ChannelIds", Description = "The channels to return guide information for.", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET,POST")]
         public string ChannelIds { get; set; }
@@ -207,11 +239,27 @@ namespace MediaBrowser.Api.LiveTv
 
         [ApiMember(Name = "Genres", Description = "The genres to return guide information for.", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET,POST")]
         public string Genres { get; set; }
+
+        [ApiMember(Name = "EnableImages", Description = "Optional, include image information in output", IsRequired = false, DataType = "boolean", ParameterType = "query", Verb = "GET")]
+        public bool? EnableImages { get; set; }
+
+        [ApiMember(Name = "ImageTypeLimit", Description = "Optional, the max number of images to return, per image type", IsRequired = false, DataType = "int", ParameterType = "query", Verb = "GET")]
+        public int? ImageTypeLimit { get; set; }
+
+        [ApiMember(Name = "EnableImageTypes", Description = "Optional. The image types to include in the output.", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET")]
+        public string EnableImageTypes { get; set; }
+
+        /// <summary>
+        /// Fields to return within the items, in addition to basic information
+        /// </summary>
+        /// <value>The fields.</value>
+        [ApiMember(Name = "Fields", Description = "Optional. Specify additional fields of information to return in the output. This allows multiple, comma delimeted. Options: Budget, Chapters, CriticRatingSummary, DateCreated, Genres, HomePageUrl, IndexOptions, MediaStreams, Overview, ParentId, Path, People, ProviderIds, PrimaryImageAspectRatio, Revenue, SortName, Studios, Taglines", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET", AllowMultiple = true)]
+        public string Fields { get; set; }
     }
 
     [Route("/LiveTv/Programs/Recommended", "GET", Summary = "Gets available live tv epgs..")]
     [Authenticated]
-    public class GetRecommendedPrograms : IReturn<QueryResult<BaseItemDto>>
+    public class GetRecommendedPrograms : IReturn<QueryResult<BaseItemDto>>, IHasDtoOptions
     {
         [ApiMember(Name = "UserId", Description = "Optional filter by user id.", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET,POST")]
         public string UserId { get; set; }
@@ -230,6 +278,22 @@ namespace MediaBrowser.Api.LiveTv
 
         [ApiMember(Name = "IsMovie", Description = "Optional filter for movies.", IsRequired = false, DataType = "bool", ParameterType = "query", Verb = "GET")]
         public bool? IsMovie { get; set; }
+
+        [ApiMember(Name = "EnableImages", Description = "Optional, include image information in output", IsRequired = false, DataType = "boolean", ParameterType = "query", Verb = "GET")]
+        public bool? EnableImages { get; set; }
+
+        [ApiMember(Name = "ImageTypeLimit", Description = "Optional, the max number of images to return, per image type", IsRequired = false, DataType = "int", ParameterType = "query", Verb = "GET")]
+        public int? ImageTypeLimit { get; set; }
+
+        [ApiMember(Name = "EnableImageTypes", Description = "Optional. The image types to include in the output.", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET")]
+        public string EnableImageTypes { get; set; }
+
+        /// <summary>
+        /// Fields to return within the items, in addition to basic information
+        /// </summary>
+        /// <value>The fields.</value>
+        [ApiMember(Name = "Fields", Description = "Optional. Specify additional fields of information to return in the output. This allows multiple, comma delimeted. Options: Budget, Chapters, CriticRatingSummary, DateCreated, Genres, HomePageUrl, IndexOptions, MediaStreams, Overview, ParentId, Path, People, ProviderIds, PrimaryImageAspectRatio, Revenue, SortName, Studios, Taglines", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET", AllowMultiple = true)]
+        public string Fields { get; set; }
     }
 
     [Route("/LiveTv/Programs/{Id}", "GET", Summary = "Gets a live tv program")]
@@ -490,7 +554,7 @@ namespace MediaBrowser.Api.LiveTv
                 IsDisliked = request.IsDisliked,
                 EnableFavoriteSorting = request.EnableFavoriteSorting
 
-            }, CancellationToken.None).ConfigureAwait(false);
+            }, GetDtoOptions(request), CancellationToken.None).ConfigureAwait(false);
 
             return ToOptimizedSerializedResultUsingCache(result);
         }
@@ -546,7 +610,7 @@ namespace MediaBrowser.Api.LiveTv
             query.IsSports = request.IsSports;
             query.Genres = (request.Genres ?? String.Empty).Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries);
 
-            var result = await _liveTvManager.GetPrograms(query, CancellationToken.None).ConfigureAwait(false);
+            var result = await _liveTvManager.GetPrograms(query, GetDtoOptions(request), CancellationToken.None).ConfigureAwait(false);
 
             return ToOptimizedResult(result);
         }
@@ -563,7 +627,7 @@ namespace MediaBrowser.Api.LiveTv
                 IsSports = request.IsSports
             };
 
-            var result = await _liveTvManager.GetRecommendedPrograms(query, CancellationToken.None).ConfigureAwait(false);
+            var result = await _liveTvManager.GetRecommendedPrograms(query, GetDtoOptions(request), CancellationToken.None).ConfigureAwait(false);
 
             return ToOptimizedResult(result);
         }
@@ -575,7 +639,7 @@ namespace MediaBrowser.Api.LiveTv
 
         public async Task<object> Get(GetRecordings request)
         {
-            var options = new DtoOptions();
+            var options = GetDtoOptions(request);
             options.DeviceId = AuthorizationContext.GetAuthorizationInfo(Request).DeviceId;
 
             var result = await _liveTvManager.GetRecordings(new RecordingQuery

+ 8 - 7
MediaBrowser.Controller/LiveTv/ILiveTvManager.cs

@@ -69,9 +69,10 @@ namespace MediaBrowser.Controller.LiveTv
         /// Gets the channels.
         /// </summary>
         /// <param name="query">The query.</param>
+        /// <param name="options">The options.</param>
         /// <param name="cancellationToken">The cancellation token.</param>
         /// <returns>IEnumerable{Channel}.</returns>
-        Task<QueryResult<ChannelInfoDto>> GetChannels(LiveTvChannelQuery query, CancellationToken cancellationToken);
+        Task<QueryResult<ChannelInfoDto>> GetChannels(LiveTvChannelQuery query, DtoOptions options, CancellationToken cancellationToken);
 
         /// <summary>
         /// Gets the recording.
@@ -173,14 +174,15 @@ namespace MediaBrowser.Controller.LiveTv
         /// <param name="user">The user.</param>
         /// <returns>Task{ProgramInfoDto}.</returns>
         Task<BaseItemDto> GetProgram(string id, CancellationToken cancellationToken, User user = null);
-        
+
         /// <summary>
         /// Gets the programs.
         /// </summary>
         /// <param name="query">The query.</param>
+        /// <param name="options">The options.</param>
         /// <param name="cancellationToken">The cancellation token.</param>
         /// <returns>IEnumerable{ProgramInfo}.</returns>
-        Task<QueryResult<BaseItemDto>> GetPrograms(ProgramQuery query, CancellationToken cancellationToken);
+        Task<QueryResult<BaseItemDto>> GetPrograms(ProgramQuery query, DtoOptions options, CancellationToken cancellationToken);
 
         /// <summary>
         /// Updates the timer.
@@ -240,10 +242,10 @@ namespace MediaBrowser.Controller.LiveTv
         /// Gets the recommended programs.
         /// </summary>
         /// <param name="query">The query.</param>
+        /// <param name="options">The options.</param>
         /// <param name="cancellationToken">The cancellation token.</param>
         /// <returns>Task{QueryResult{ProgramInfoDto}}.</returns>
-        Task<QueryResult<BaseItemDto>> GetRecommendedPrograms(RecommendedProgramQuery query,
-            CancellationToken cancellationToken);
+        Task<QueryResult<BaseItemDto>> GetRecommendedPrograms(RecommendedProgramQuery query, DtoOptions options, CancellationToken cancellationToken);
 
         /// <summary>
         /// Gets the recommended programs internal.
@@ -251,8 +253,7 @@ namespace MediaBrowser.Controller.LiveTv
         /// <param name="query">The query.</param>
         /// <param name="cancellationToken">The cancellation token.</param>
         /// <returns>Task&lt;QueryResult&lt;LiveTvProgram&gt;&gt;.</returns>
-        Task<QueryResult<LiveTvProgram>> GetRecommendedProgramsInternal(RecommendedProgramQuery query,
-            CancellationToken cancellationToken);
+        Task<QueryResult<LiveTvProgram>> GetRecommendedProgramsInternal(RecommendedProgramQuery query, CancellationToken cancellationToken);
 
         /// <summary>
         /// Gets the live tv information.

+ 9 - 9
MediaBrowser.Dlna/Didl/DidlBuilder.cs

@@ -971,17 +971,17 @@ namespace MediaBrowser.Dlna.Didl
             int? width = null;
             int? height = null;
 
-            try
-            {
-                var size = _imageProcessor.GetImageSize(imageInfo);
+            //try
+            //{
+            //    var size = _imageProcessor.GetImageSize(imageInfo);
 
-                width = Convert.ToInt32(size.Width);
-                height = Convert.ToInt32(size.Height);
-            }
-            catch
-            {
+            //    width = Convert.ToInt32(size.Width);
+            //    height = Convert.ToInt32(size.Height);
+            //}
+            //catch
+            //{
 
-            }
+            //}
 
             return new ImageDownloadInfo
             {

+ 13 - 1
MediaBrowser.Model/Channels/ChannelQuery.cs

@@ -1,7 +1,19 @@
-namespace MediaBrowser.Model.Channels
+using MediaBrowser.Model.Entities;
+using MediaBrowser.Model.Querying;
+
+namespace MediaBrowser.Model.Channels
 {
     public class ChannelQuery
     {
+        /// <summary>
+        /// Fields to return within the items, in addition to basic information
+        /// </summary>
+        /// <value>The fields.</value>
+        public ItemFields[] Fields { get; set; }
+        public bool? EnableImages { get; set; }
+        public int? ImageTypeLimit { get; set; }
+        public ImageType[] EnableImageTypes { get; set; }
+        
         /// <summary>
         /// Gets or sets the user identifier.
         /// </summary>

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

@@ -1,5 +1,6 @@
 using MediaBrowser.Model.Entities;
 using System;
+using MediaBrowser.Model.Querying;
 
 namespace MediaBrowser.Model.LiveTv
 {
@@ -15,6 +16,15 @@ namespace MediaBrowser.Model.LiveTv
             Genres = new string[] { };
         }
 
+        /// <summary>
+        /// Fields to return within the items, in addition to basic information
+        /// </summary>
+        /// <value>The fields.</value>
+        public ItemFields[] Fields { get; set; }
+        public bool? EnableImages { get; set; }
+        public int? ImageTypeLimit { get; set; }
+        public ImageType[] EnableImageTypes { get; set; }
+        
         /// <summary>
         /// Gets or sets the channel ids.
         /// </summary>

+ 13 - 1
MediaBrowser.Model/LiveTv/RecommendedProgramQuery.cs

@@ -1,7 +1,19 @@
-namespace MediaBrowser.Model.LiveTv
+using MediaBrowser.Model.Entities;
+using MediaBrowser.Model.Querying;
+
+namespace MediaBrowser.Model.LiveTv
 {
     public class RecommendedProgramQuery
     {
+        /// <summary>
+        /// Fields to return within the items, in addition to basic information
+        /// </summary>
+        /// <value>The fields.</value>
+        public ItemFields[] Fields { get; set; }
+        public bool? EnableImages { get; set; }
+        public int? ImageTypeLimit { get; set; }
+        public ImageType[] EnableImageTypes { get; set; }
+        
         /// <summary>
         /// Gets or sets the user identifier.
         /// </summary>

+ 13 - 1
MediaBrowser.Model/LiveTv/RecordingQuery.cs

@@ -1,4 +1,7 @@
-namespace MediaBrowser.Model.LiveTv
+using MediaBrowser.Model.Entities;
+using MediaBrowser.Model.Querying;
+
+namespace MediaBrowser.Model.LiveTv
 {
     /// <summary>
     /// Class RecordingQuery.
@@ -58,5 +61,14 @@
         /// </summary>
         /// <value>The series timer identifier.</value>
         public string SeriesTimerId { get; set; }
+
+        /// <summary>
+        /// Fields to return within the items, in addition to basic information
+        /// </summary>
+        /// <value>The fields.</value>
+        public ItemFields[] Fields { get; set; }
+        public bool? EnableImages { get; set; }
+        public int? ImageTypeLimit { get; set; }
+        public ImageType[] EnableImageTypes { get; set; }
     }
 }

+ 0 - 5
MediaBrowser.Server.Implementations/Dto/DtoService.cs

@@ -1767,11 +1767,6 @@ namespace MediaBrowser.Server.Implementations.Dto
             {
                 size = _imageProcessor.GetImageSize(imageInfo);
             }
-            catch (FileNotFoundException)
-            {
-                _logger.Error("Image file does not exist: {0}", path);
-                return;
-            }
             catch (Exception ex)
             {
                 _logger.ErrorException("Failed to determine primary image aspect ratio for {0}", ex, path);

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

@@ -77,6 +77,10 @@ namespace MediaBrowser.Server.Implementations.Library
             {
                 return false;
             }
+            if (string.Equals(stream.Codec, "ssa", StringComparison.OrdinalIgnoreCase))
+            {
+                return false;
+            }
 
             return true;
         }

+ 3 - 2
MediaBrowser.Server.Implementations/LiveTv/LiveTvDtoService.cs

@@ -198,10 +198,11 @@ namespace MediaBrowser.Server.Implementations.LiveTv
         /// Gets the channel info dto.
         /// </summary>
         /// <param name="info">The info.</param>
+        /// <param name="options">The options.</param>
         /// <param name="currentProgram">The current program.</param>
         /// <param name="user">The user.</param>
         /// <returns>ChannelInfoDto.</returns>
-        public ChannelInfoDto GetChannelInfoDto(LiveTvChannel info, LiveTvProgram currentProgram, User user = null)
+        public ChannelInfoDto GetChannelInfoDto(LiveTvChannel info, DtoOptions options, LiveTvProgram currentProgram, User user = null)
         {
             var dto = new ChannelInfoDto
             {
@@ -238,7 +239,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv
 
             if (currentProgram != null)
             {
-                dto.CurrentProgram = _dtoService.GetBaseItemDto(currentProgram, new DtoOptions(), user);
+                dto.CurrentProgram = _dtoService.GetBaseItemDto(currentProgram, options, user);
             }
 
             return dto;

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

@@ -238,7 +238,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv
             return result;
         }
 
-        public async Task<QueryResult<ChannelInfoDto>> GetChannels(LiveTvChannelQuery query, CancellationToken cancellationToken)
+        public async Task<QueryResult<ChannelInfoDto>> GetChannels(LiveTvChannelQuery query, DtoOptions options, CancellationToken cancellationToken)
         {
             var user = string.IsNullOrEmpty(query.UserId) ? null : _userManager.GetUserById(query.UserId);
 
@@ -261,7 +261,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv
                 var channelIdString = channel.Id.ToString("N");
                 var currentProgram = programs.FirstOrDefault(i => string.Equals(i.ChannelId, channelIdString, StringComparison.OrdinalIgnoreCase));
 
-                returnList.Add(_tvDtoService.GetChannelInfoDto(channel, currentProgram, user));
+                returnList.Add(_tvDtoService.GetChannelInfoDto(channel, options, currentProgram, user));
             }
 
             var result = new QueryResult<ChannelInfoDto>
@@ -762,7 +762,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv
             return dto;
         }
 
-        public async Task<QueryResult<BaseItemDto>> GetPrograms(ProgramQuery query, CancellationToken cancellationToken)
+        public async Task<QueryResult<BaseItemDto>> GetPrograms(ProgramQuery query, DtoOptions options, CancellationToken cancellationToken)
         {
             var internalQuery = new InternalItemsQuery
             {
@@ -822,7 +822,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv
                 .Select(i =>
                 {
                     RefreshIfNeeded(i);
-                    return _dtoService.GetBaseItemDto(i, new DtoOptions(), user);
+                    return _dtoService.GetBaseItemDto(i, options, user);
                 })
                 .ToArray();
 
@@ -907,14 +907,14 @@ namespace MediaBrowser.Server.Implementations.LiveTv
             return result;
         }
 
-        public async Task<QueryResult<BaseItemDto>> GetRecommendedPrograms(RecommendedProgramQuery query, CancellationToken cancellationToken)
+        public async Task<QueryResult<BaseItemDto>> GetRecommendedPrograms(RecommendedProgramQuery query, DtoOptions options, CancellationToken cancellationToken)
         {
             var internalResult = await GetRecommendedProgramsInternal(query, cancellationToken).ConfigureAwait(false);
 
             var user = _userManager.GetUserById(query.UserId);
 
             var returnArray = internalResult.Items
-                .Select(i => _dtoService.GetBaseItemDto(i, new DtoOptions(), user))
+                .Select(i => _dtoService.GetBaseItemDto(i, options, user))
                 .ToArray();
 
             await AddRecordingInfo(returnArray, cancellationToken).ConfigureAwait(false);
@@ -1712,7 +1712,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv
                 .OrderBy(i => i.StartDate)
                 .FirstOrDefault();
 
-            var dto = _tvDtoService.GetChannelInfoDto(channel, currentProgram, user);
+            var dto = _tvDtoService.GetChannelInfoDto(channel, new DtoOptions(), currentProgram, user);
 
             return dto;
         }