Pārlūkot izejas kodu

added suggested live tv page

Luke Pulverenti 11 gadi atpakaļ
vecāks
revīzija
cc3e8dbbb9

+ 32 - 0
MediaBrowser.Api/LiveTv/LiveTvService.cs

@@ -154,6 +154,23 @@ namespace MediaBrowser.Api.LiveTv
         public string MaxEndDate { get; set; }
         public string MaxEndDate { get; set; }
     }
     }
 
 
+    [Route("/LiveTv/Programs/Recommended", "GET")]
+    [Api(Description = "Gets available live tv epgs..")]
+    public class GetRecommendedPrograms : IReturn<QueryResult<ProgramInfoDto>>
+    {
+        [ApiMember(Name = "UserId", Description = "Optional filter by user id.", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET,POST")]
+        public string UserId { get; set; }
+
+        [ApiMember(Name = "Limit", Description = "Optional. The maximum number of records to return", IsRequired = false, DataType = "int", ParameterType = "query", Verb = "GET")]
+        public int? Limit { get; set; }
+
+        [ApiMember(Name = "IsAiring", Description = "Optional. Filter by programs that are currently airing, or not.", IsRequired = false, DataType = "bool", ParameterType = "query", Verb = "GET")]
+        public bool? IsAiring { get; set; }
+
+        [ApiMember(Name = "HasAired", Description = "Optional. Filter by programs that have completed airing, or not.", IsRequired = false, DataType = "bool", ParameterType = "query", Verb = "GET")]
+        public bool? HasAired { get; set; }
+    }
+
     [Route("/LiveTv/Programs/{Id}", "GET")]
     [Route("/LiveTv/Programs/{Id}", "GET")]
     [Api(Description = "Gets a live tv program")]
     [Api(Description = "Gets a live tv program")]
     public class GetProgram : IReturn<ProgramInfoDto>
     public class GetProgram : IReturn<ProgramInfoDto>
@@ -331,6 +348,21 @@ namespace MediaBrowser.Api.LiveTv
             return ToOptimizedResult(result);
             return ToOptimizedResult(result);
         }
         }
 
 
+        public object Get(GetRecommendedPrograms request)
+        {
+            var query = new RecommendedProgramQuery
+            {
+                UserId = request.UserId,
+                IsAiring = request.IsAiring,
+                Limit = request.Limit,
+                HasAired = request.HasAired
+            };
+
+            var result = _liveTvManager.GetRecommendedPrograms(query, CancellationToken.None).Result;
+
+            return ToOptimizedResult(result);
+        }
+
         public object Post(GetPrograms request)
         public object Post(GetPrograms request)
         {
         {
             return Get(request);
             return Get(request);

+ 9 - 0
MediaBrowser.Controller/LiveTv/ILiveTvManager.cs

@@ -240,5 +240,14 @@ namespace MediaBrowser.Controller.LiveTv
         /// </summary>
         /// </summary>
         /// <returns>GuideInfo.</returns>
         /// <returns>GuideInfo.</returns>
         GuideInfo GetGuideInfo();
         GuideInfo GetGuideInfo();
+
+        /// <summary>
+        /// Gets the recommended programs.
+        /// </summary>
+        /// <param name="query">The query.</param>
+        /// <param name="cancellationToken">The cancellation token.</param>
+        /// <returns>Task{QueryResult{ProgramInfoDto}}.</returns>
+        Task<QueryResult<ProgramInfoDto>> GetRecommendedPrograms(RecommendedProgramQuery query,
+            CancellationToken cancellationToken);
     }
     }
 }
 }

+ 18 - 7
MediaBrowser.Controller/LiveTv/ILiveTvService.cs

@@ -1,4 +1,5 @@
-using System.Collections.Generic;
+using System;
+using System.Collections.Generic;
 using System.Threading;
 using System.Threading;
 using System.Threading.Tasks;
 using System.Threading.Tasks;
 
 
@@ -37,7 +38,7 @@ namespace MediaBrowser.Controller.LiveTv
         /// <param name="cancellationToken">The cancellation token.</param>
         /// <param name="cancellationToken">The cancellation token.</param>
         /// <returns>Task.</returns>
         /// <returns>Task.</returns>
         Task CancelSeriesTimerAsync(string timerId, CancellationToken cancellationToken);
         Task CancelSeriesTimerAsync(string timerId, CancellationToken cancellationToken);
-        
+
         /// <summary>
         /// <summary>
         /// Deletes the recording asynchronous.
         /// Deletes the recording asynchronous.
         /// </summary>
         /// </summary>
@@ -77,7 +78,7 @@ namespace MediaBrowser.Controller.LiveTv
         /// <param name="cancellationToken">The cancellation token.</param>
         /// <param name="cancellationToken">The cancellation token.</param>
         /// <returns>Task.</returns>
         /// <returns>Task.</returns>
         Task UpdateSeriesTimerAsync(SeriesTimerInfo info, CancellationToken cancellationToken);
         Task UpdateSeriesTimerAsync(SeriesTimerInfo info, CancellationToken cancellationToken);
-        
+
         /// <summary>
         /// <summary>
         /// Gets the channel image asynchronous. This only needs to be implemented if an image path or url cannot be supplied to ChannelInfo
         /// Gets the channel image asynchronous. This only needs to be implemented if an image path or url cannot be supplied to ChannelInfo
         /// </summary>
         /// </summary>
@@ -102,7 +103,7 @@ namespace MediaBrowser.Controller.LiveTv
         /// <param name="cancellationToken">The cancellation token.</param>
         /// <param name="cancellationToken">The cancellation token.</param>
         /// <returns>Task{ImageResponseInfo}.</returns>
         /// <returns>Task{ImageResponseInfo}.</returns>
         Task<StreamResponseInfo> GetProgramImageAsync(string programId, string channelId, CancellationToken cancellationToken);
         Task<StreamResponseInfo> GetProgramImageAsync(string programId, string channelId, CancellationToken cancellationToken);
-        
+
         /// <summary>
         /// <summary>
         /// Gets the recordings asynchronous.
         /// Gets the recordings asynchronous.
         /// </summary>
         /// </summary>
@@ -123,21 +124,23 @@ namespace MediaBrowser.Controller.LiveTv
         /// <param name="cancellationToken">The cancellation token.</param>
         /// <param name="cancellationToken">The cancellation token.</param>
         /// <returns>Task{TimerInfo}.</returns>
         /// <returns>Task{TimerInfo}.</returns>
         Task<SeriesTimerInfo> GetNewTimerDefaultsAsync(CancellationToken cancellationToken);
         Task<SeriesTimerInfo> GetNewTimerDefaultsAsync(CancellationToken cancellationToken);
-        
+
         /// <summary>
         /// <summary>
         /// Gets the series timers asynchronous.
         /// Gets the series timers asynchronous.
         /// </summary>
         /// </summary>
         /// <param name="cancellationToken">The cancellation token.</param>
         /// <param name="cancellationToken">The cancellation token.</param>
         /// <returns>Task{IEnumerable{SeriesTimerInfo}}.</returns>
         /// <returns>Task{IEnumerable{SeriesTimerInfo}}.</returns>
         Task<IEnumerable<SeriesTimerInfo>> GetSeriesTimersAsync(CancellationToken cancellationToken);
         Task<IEnumerable<SeriesTimerInfo>> GetSeriesTimersAsync(CancellationToken cancellationToken);
-        
+
         /// <summary>
         /// <summary>
         /// Gets the programs asynchronous.
         /// Gets the programs asynchronous.
         /// </summary>
         /// </summary>
         /// <param name="channelId">The channel identifier.</param>
         /// <param name="channelId">The channel identifier.</param>
+        /// <param name="startDateUtc">The start date UTC.</param>
+        /// <param name="endDateUtc">The end date UTC.</param>
         /// <param name="cancellationToken">The cancellation token.</param>
         /// <param name="cancellationToken">The cancellation token.</param>
         /// <returns>Task{IEnumerable{ProgramInfo}}.</returns>
         /// <returns>Task{IEnumerable{ProgramInfo}}.</returns>
-        Task<IEnumerable<ProgramInfo>> GetProgramsAsync(string channelId, CancellationToken cancellationToken);
+        Task<IEnumerable<ProgramInfo>> GetProgramsAsync(string channelId, DateTime startDateUtc, DateTime endDateUtc, CancellationToken cancellationToken);
 
 
         /// <summary>
         /// <summary>
         /// Gets the recording stream.
         /// Gets the recording stream.
@@ -162,5 +165,13 @@ namespace MediaBrowser.Controller.LiveTv
         /// <param name="cancellationToken">The cancellation token.</param>
         /// <param name="cancellationToken">The cancellation token.</param>
         /// <returns>Task.</returns>
         /// <returns>Task.</returns>
         Task CloseLiveStream(string id, CancellationToken cancellationToken);
         Task CloseLiveStream(string id, CancellationToken cancellationToken);
+
+        /// <summary>
+        /// Records the live stream.
+        /// </summary>
+        /// <param name="id">The identifier.</param>
+        /// <param name="cancellationToken">The cancellation token.</param>
+        /// <returns>Task.</returns>
+        Task RecordLiveStream(string id, CancellationToken cancellationToken);
     }
     }
 }
 }

+ 21 - 0
MediaBrowser.Controller/LiveTv/LiveTvProgram.cs

@@ -1,5 +1,6 @@
 using MediaBrowser.Controller.Entities;
 using MediaBrowser.Controller.Entities;
 using MediaBrowser.Model.LiveTv;
 using MediaBrowser.Model.LiveTv;
+using System;
 
 
 namespace MediaBrowser.Controller.LiveTv
 namespace MediaBrowser.Controller.LiveTv
 {
 {
@@ -28,6 +29,26 @@ namespace MediaBrowser.Controller.LiveTv
             }
             }
         }
         }
 
 
+        public bool IsAiring
+        {
+            get
+            {
+                var now = DateTime.UtcNow;
+
+                return now >= ProgramInfo.StartDate && now < ProgramInfo.EndDate;
+            }
+        }
+
+        public bool HasAired
+        {
+            get
+            {
+                var now = DateTime.UtcNow;
+
+                return now >= ProgramInfo.EndDate;
+            }
+        }
+
         public override string GetClientTypeName()
         public override string GetClientTypeName()
         {
         {
             return "Program";
             return "Program";

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

@@ -32,4 +32,31 @@ namespace MediaBrowser.Model.LiveTv
             ChannelIdList = new string[] { };
             ChannelIdList = new string[] { };
         }
         }
     }
     }
+
+    public class RecommendedProgramQuery
+    {
+        /// <summary>
+        /// Gets or sets the user identifier.
+        /// </summary>
+        /// <value>The user identifier.</value>
+        public string UserId { get; set; }
+
+        /// <summary>
+        /// Gets or sets a value indicating whether this instance is airing.
+        /// </summary>
+        /// <value><c>true</c> if this instance is airing; otherwise, <c>false</c>.</value>
+        public bool? IsAiring { get; set; }
+
+        /// <summary>
+        /// Gets or sets a value indicating whether this instance has aired.
+        /// </summary>
+        /// <value><c>null</c> if [has aired] contains no value, <c>true</c> if [has aired]; otherwise, <c>false</c>.</value>
+        public bool? HasAired { get; set; }
+
+        /// <summary>
+        /// The maximum number of items to return
+        /// </summary>
+        /// <value>The limit.</value>
+        public int? Limit { get; set; }
+    }
 }
 }

+ 138 - 2
MediaBrowser.Server.Implementations/LiveTv/LiveTvManager.cs

@@ -32,6 +32,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv
         private readonly ILogger _logger;
         private readonly ILogger _logger;
         private readonly IItemRepository _itemRepo;
         private readonly IItemRepository _itemRepo;
         private readonly IUserManager _userManager;
         private readonly IUserManager _userManager;
+        private readonly IUserDataManager _userDataManager;
         private readonly ILibraryManager _libraryManager;
         private readonly ILibraryManager _libraryManager;
         private readonly IMediaEncoder _mediaEncoder;
         private readonly IMediaEncoder _mediaEncoder;
 
 
@@ -54,6 +55,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv
             _userManager = userManager;
             _userManager = userManager;
             _libraryManager = libraryManager;
             _libraryManager = libraryManager;
             _mediaEncoder = mediaEncoder;
             _mediaEncoder = mediaEncoder;
+            _userDataManager = userDataManager;
 
 
             _tvDtoService = new LiveTvDtoService(dtoService, userDataManager, imageProcessor, logger, _itemRepo);
             _tvDtoService = new LiveTvDtoService(dtoService, userDataManager, imageProcessor, logger, _itemRepo);
         }
         }
@@ -428,7 +430,6 @@ namespace MediaBrowser.Server.Implementations.LiveTv
             }
             }
 
 
             var returnArray = programs
             var returnArray = programs
-                .OrderBy(i => i.ProgramInfo.StartDate)
                 .Select(i =>
                 .Select(i =>
                 {
                 {
                     var channel = GetChannel(i);
                     var channel = GetChannel(i);
@@ -450,6 +451,138 @@ namespace MediaBrowser.Server.Implementations.LiveTv
             return result;
             return result;
         }
         }
 
 
+        public async Task<QueryResult<ProgramInfoDto>> GetRecommendedPrograms(RecommendedProgramQuery query, CancellationToken cancellationToken)
+        {
+            IEnumerable<LiveTvProgram> programs = _programs.Values;
+
+            var user = _userManager.GetUserById(new Guid(query.UserId));
+
+            // Avoid implicitly captured closure
+            var currentUser = user;
+            programs = programs.Where(i => i.IsParentalAllowed(currentUser));
+
+            if (query.IsAiring.HasValue)
+            {
+                var val = query.IsAiring.Value;
+                programs = programs.Where(i => i.IsAiring == val);
+            }
+
+            if (query.HasAired.HasValue)
+            {
+                var val = query.HasAired.Value;
+                programs = programs.Where(i => i.HasAired == val);
+            }
+
+            var serviceName = ActiveService.Name;
+
+            var programList = programs.ToList();
+
+            var genres = programList.SelectMany(i => i.Genres)
+                .Distinct(StringComparer.OrdinalIgnoreCase)
+                .Select(i => _libraryManager.GetGenre(i))
+                .ToDictionary(i => i.Name, StringComparer.OrdinalIgnoreCase);
+
+            programs = programList.OrderByDescending(i => GetRecommendationScore(i.ProgramInfo, user.Id, serviceName, genres))
+                .ThenBy(i => i.ProgramInfo.StartDate);
+
+            if (query.Limit.HasValue)
+            {
+                programs = programs.Take(query.Limit.Value)
+                    .OrderBy(i => i.ProgramInfo.StartDate);
+            }
+
+            var returnArray = programs
+                .Select(i =>
+                {
+                    var channel = GetChannel(i);
+
+                    var channelName = channel == null ? null : channel.ChannelInfo.Name;
+
+                    return _tvDtoService.GetProgramInfoDto(i, channelName, user);
+                })
+                .ToArray();
+
+            await AddRecordingInfo(returnArray, cancellationToken).ConfigureAwait(false);
+
+            var result = new QueryResult<ProgramInfoDto>
+            {
+                Items = returnArray,
+                TotalRecordCount = returnArray.Length
+            };
+
+            return result;
+        }
+
+        private int GetRecommendationScore(ProgramInfo program, Guid userId, string serviceName, Dictionary<string, Genre> genres)
+        {
+            var score = 0;
+
+            if (program.IsLive)
+            {
+                score++;
+            }
+
+            if (program.IsSeries && !program.IsRepeat)
+            {
+                score++;
+            }
+
+            var internalChannelId = _tvDtoService.GetInternalChannelId(serviceName, program.ChannelId);
+            var channel = GetInternalChannel(internalChannelId);
+
+            var channelUserdata = _userDataManager.GetUserData(userId, channel.GetUserDataKey());
+
+            if ((channelUserdata.Likes ?? false))
+            {
+                score += 2;
+            }
+            else if (!(channelUserdata.Likes ?? true))
+            {
+                score -= 2;
+            }
+
+            if (channelUserdata.IsFavorite)
+            {
+                score += 3;
+            }
+
+            score += GetGenreScore(program.Genres, userId, genres);
+
+            return score;
+        }
+
+        private int GetGenreScore(IEnumerable<string> programGenres, Guid userId, Dictionary<string, Genre> genres)
+        {
+            return programGenres.Select(i =>
+            {
+                var score = 0;
+
+                Genre genre;
+
+                if (genres.TryGetValue(i, out genre))
+                {
+                    var genreUserdata = _userDataManager.GetUserData(userId, genre.GetUserDataKey());
+
+                    if ((genreUserdata.Likes ?? false))
+                    {
+                        score++;
+                    }
+                    else if (!(genreUserdata.Likes ?? true))
+                    {
+                        score--;
+                    }
+
+                    if (genreUserdata.IsFavorite)
+                    {
+                        score += 2;
+                    }
+                }
+
+                return score;
+
+            }).Sum();
+        }
+
         private async Task AddRecordingInfo(IEnumerable<ProgramInfoDto> programs, CancellationToken cancellationToken)
         private async Task AddRecordingInfo(IEnumerable<ProgramInfoDto> programs, CancellationToken cancellationToken)
         {
         {
             var timers = await ActiveService.GetTimersAsync(cancellationToken).ConfigureAwait(false);
             var timers = await ActiveService.GetTimersAsync(cancellationToken).ConfigureAwait(false);
@@ -533,7 +666,10 @@ namespace MediaBrowser.Server.Implementations.LiveTv
 
 
                 try
                 try
                 {
                 {
-                    var channelPrograms = await service.GetProgramsAsync(currentChannel.ChannelInfo.Id, cancellationToken).ConfigureAwait(false);
+                    var start = DateTime.UtcNow;
+                    var end = start.AddDays(3);
+
+                    var channelPrograms = await service.GetProgramsAsync(currentChannel.ChannelInfo.Id, start, end, cancellationToken).ConfigureAwait(false);
 
 
                     var programTasks = channelPrograms.Select(program => GetProgram(program, currentChannel.ChannelInfo.ChannelType, service.Name, cancellationToken));
                     var programTasks = channelPrograms.Select(program => GetProgram(program, currentChannel.ChannelInfo.ChannelType, service.Name, cancellationToken));
                     var programEntities = await Task.WhenAll(programTasks).ConfigureAwait(false);
                     var programEntities = await Task.WhenAll(programTasks).ConfigureAwait(false);

+ 12 - 1
MediaBrowser.WebDashboard/ApiClient.js

@@ -438,7 +438,7 @@ MediaBrowser.ApiClient = function ($, navigator, JSON, WebSocket, setTimeout, wi
 
 
             options = options || {};
             options = options || {};
             
             
-            if (options.channelIds) {
+            if (options.channelIds && options.channelIds.length > 1800) {
 
 
                 return self.ajax({
                 return self.ajax({
                     type: "POST",
                     type: "POST",
@@ -458,6 +458,17 @@ MediaBrowser.ApiClient = function ($, navigator, JSON, WebSocket, setTimeout, wi
             }
             }
         };
         };
 
 
+        self.getLiveTvRecommendedPrograms = function (options) {
+
+            options = options || {};
+
+            return self.ajax({
+                type: "GET",
+                url: self.getUrl("LiveTv/Programs/Recommended", options),
+                dataType: "json"
+            });
+        };
+
         self.getLiveTvRecordings = function (options) {
         self.getLiveTvRecordings = function (options) {
 
 
             var url = self.getUrl("LiveTv/Recordings", options || {});
             var url = self.getUrl("LiveTv/Recordings", options || {});

+ 1 - 1
MediaBrowser.WebDashboard/packages.config

@@ -1,4 +1,4 @@
 <?xml version="1.0" encoding="utf-8"?>
 <?xml version="1.0" encoding="utf-8"?>
 <packages>
 <packages>
-  <package id="MediaBrowser.ApiClient.Javascript" version="3.0.224" targetFramework="net45" />
+  <package id="MediaBrowser.ApiClient.Javascript" version="3.0.226" targetFramework="net45" />
 </packages>
 </packages>

+ 2 - 2
Nuget/MediaBrowser.Common.Internal.nuspec

@@ -2,7 +2,7 @@
 <package xmlns="http://schemas.microsoft.com/packaging/2011/08/nuspec.xsd">
 <package xmlns="http://schemas.microsoft.com/packaging/2011/08/nuspec.xsd">
     <metadata>
     <metadata>
         <id>MediaBrowser.Common.Internal</id>
         <id>MediaBrowser.Common.Internal</id>
-        <version>3.0.298</version>
+        <version>3.0.299</version>
         <title>MediaBrowser.Common.Internal</title>
         <title>MediaBrowser.Common.Internal</title>
         <authors>Luke</authors>
         <authors>Luke</authors>
         <owners>ebr,Luke,scottisafool</owners>
         <owners>ebr,Luke,scottisafool</owners>
@@ -12,7 +12,7 @@
         <description>Contains common components shared by Media Browser Theater and Media Browser Server. Not intended for plugin developer consumption.</description>
         <description>Contains common components shared by Media Browser Theater and Media Browser Server. Not intended for plugin developer consumption.</description>
         <copyright>Copyright © Media Browser 2013</copyright>
         <copyright>Copyright © Media Browser 2013</copyright>
         <dependencies>
         <dependencies>
-            <dependency id="MediaBrowser.Common" version="3.0.298" />
+            <dependency id="MediaBrowser.Common" version="3.0.299" />
             <dependency id="NLog" version="2.1.0" />
             <dependency id="NLog" version="2.1.0" />
             <dependency id="SimpleInjector" version="2.4.0" />
             <dependency id="SimpleInjector" version="2.4.0" />
             <dependency id="sharpcompress" version="0.10.2" />
             <dependency id="sharpcompress" version="0.10.2" />

+ 1 - 1
Nuget/MediaBrowser.Common.nuspec

@@ -2,7 +2,7 @@
 <package xmlns="http://schemas.microsoft.com/packaging/2011/08/nuspec.xsd">
 <package xmlns="http://schemas.microsoft.com/packaging/2011/08/nuspec.xsd">
     <metadata>
     <metadata>
         <id>MediaBrowser.Common</id>
         <id>MediaBrowser.Common</id>
-        <version>3.0.298</version>
+        <version>3.0.299</version>
         <title>MediaBrowser.Common</title>
         <title>MediaBrowser.Common</title>
         <authors>Media Browser Team</authors>
         <authors>Media Browser Team</authors>
         <owners>ebr,Luke,scottisafool</owners>
         <owners>ebr,Luke,scottisafool</owners>

+ 2 - 2
Nuget/MediaBrowser.Server.Core.nuspec

@@ -2,7 +2,7 @@
 <package xmlns="http://schemas.microsoft.com/packaging/2010/07/nuspec.xsd">
 <package xmlns="http://schemas.microsoft.com/packaging/2010/07/nuspec.xsd">
     <metadata>
     <metadata>
         <id>MediaBrowser.Server.Core</id>
         <id>MediaBrowser.Server.Core</id>
-        <version>3.0.298</version>
+        <version>3.0.299</version>
         <title>Media Browser.Server.Core</title>
         <title>Media Browser.Server.Core</title>
         <authors>Media Browser Team</authors>
         <authors>Media Browser Team</authors>
         <owners>ebr,Luke,scottisafool</owners>
         <owners>ebr,Luke,scottisafool</owners>
@@ -12,7 +12,7 @@
         <description>Contains core components required to build plugins for Media Browser Server.</description>
         <description>Contains core components required to build plugins for Media Browser Server.</description>
         <copyright>Copyright © Media Browser 2013</copyright>
         <copyright>Copyright © Media Browser 2013</copyright>
         <dependencies>
         <dependencies>
-            <dependency id="MediaBrowser.Common" version="3.0.298" />
+            <dependency id="MediaBrowser.Common" version="3.0.299" />
         </dependencies>
         </dependencies>
     </metadata>
     </metadata>
     <files>
     <files>