diff options
| author | Luke Pulverenti <luke.pulverenti@gmail.com> | 2014-01-12 10:58:47 -0500 |
|---|---|---|
| committer | Luke Pulverenti <luke.pulverenti@gmail.com> | 2014-01-12 10:58:47 -0500 |
| commit | cc3e8dbbb942977d8f46a0a16e3802c0e5d0c94b (patch) | |
| tree | 85805a24d77ee67daf5edbadd090fa52f4d17fc0 | |
| parent | c8a106f485ff7e340ee8ca67adac3351ec6a31b6 (diff) | |
added suggested live tv page
| -rw-r--r-- | MediaBrowser.Api/LiveTv/LiveTvService.cs | 32 | ||||
| -rw-r--r-- | MediaBrowser.Controller/LiveTv/ILiveTvManager.cs | 9 | ||||
| -rw-r--r-- | MediaBrowser.Controller/LiveTv/ILiveTvService.cs | 25 | ||||
| -rw-r--r-- | MediaBrowser.Controller/LiveTv/LiveTvProgram.cs | 21 | ||||
| -rw-r--r-- | MediaBrowser.Model/LiveTv/ProgramQuery.cs | 27 | ||||
| -rw-r--r-- | MediaBrowser.Server.Implementations/LiveTv/LiveTvManager.cs | 140 | ||||
| -rw-r--r-- | MediaBrowser.WebDashboard/ApiClient.js | 13 | ||||
| -rw-r--r-- | MediaBrowser.WebDashboard/packages.config | 2 | ||||
| -rw-r--r-- | Nuget/MediaBrowser.Common.Internal.nuspec | 4 | ||||
| -rw-r--r-- | Nuget/MediaBrowser.Common.nuspec | 2 | ||||
| -rw-r--r-- | Nuget/MediaBrowser.Server.Core.nuspec | 4 |
11 files changed, 263 insertions, 16 deletions
diff --git a/MediaBrowser.Api/LiveTv/LiveTvService.cs b/MediaBrowser.Api/LiveTv/LiveTvService.cs index 50e7319b9..f92c4932e 100644 --- a/MediaBrowser.Api/LiveTv/LiveTvService.cs +++ b/MediaBrowser.Api/LiveTv/LiveTvService.cs @@ -154,6 +154,23 @@ namespace MediaBrowser.Api.LiveTv 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")] [Api(Description = "Gets a live tv program")] public class GetProgram : IReturn<ProgramInfoDto> @@ -331,6 +348,21 @@ namespace MediaBrowser.Api.LiveTv 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) { return Get(request); diff --git a/MediaBrowser.Controller/LiveTv/ILiveTvManager.cs b/MediaBrowser.Controller/LiveTv/ILiveTvManager.cs index 1856182da..31c336932 100644 --- a/MediaBrowser.Controller/LiveTv/ILiveTvManager.cs +++ b/MediaBrowser.Controller/LiveTv/ILiveTvManager.cs @@ -240,5 +240,14 @@ namespace MediaBrowser.Controller.LiveTv /// </summary> /// <returns>GuideInfo.</returns> 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); } } diff --git a/MediaBrowser.Controller/LiveTv/ILiveTvService.cs b/MediaBrowser.Controller/LiveTv/ILiveTvService.cs index 1e535139c..81613c1df 100644 --- a/MediaBrowser.Controller/LiveTv/ILiveTvService.cs +++ b/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.Tasks; @@ -37,7 +38,7 @@ namespace MediaBrowser.Controller.LiveTv /// <param name="cancellationToken">The cancellation token.</param> /// <returns>Task.</returns> Task CancelSeriesTimerAsync(string timerId, CancellationToken cancellationToken); - + /// <summary> /// Deletes the recording asynchronous. /// </summary> @@ -77,7 +78,7 @@ namespace MediaBrowser.Controller.LiveTv /// <param name="cancellationToken">The cancellation token.</param> /// <returns>Task.</returns> Task UpdateSeriesTimerAsync(SeriesTimerInfo info, CancellationToken cancellationToken); - + /// <summary> /// Gets the channel image asynchronous. This only needs to be implemented if an image path or url cannot be supplied to ChannelInfo /// </summary> @@ -102,7 +103,7 @@ namespace MediaBrowser.Controller.LiveTv /// <param name="cancellationToken">The cancellation token.</param> /// <returns>Task{ImageResponseInfo}.</returns> Task<StreamResponseInfo> GetProgramImageAsync(string programId, string channelId, CancellationToken cancellationToken); - + /// <summary> /// Gets the recordings asynchronous. /// </summary> @@ -123,21 +124,23 @@ namespace MediaBrowser.Controller.LiveTv /// <param name="cancellationToken">The cancellation token.</param> /// <returns>Task{TimerInfo}.</returns> Task<SeriesTimerInfo> GetNewTimerDefaultsAsync(CancellationToken cancellationToken); - + /// <summary> /// Gets the series timers asynchronous. /// </summary> /// <param name="cancellationToken">The cancellation token.</param> /// <returns>Task{IEnumerable{SeriesTimerInfo}}.</returns> Task<IEnumerable<SeriesTimerInfo>> GetSeriesTimersAsync(CancellationToken cancellationToken); - + /// <summary> /// Gets the programs asynchronous. /// </summary> /// <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> /// <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> /// Gets the recording stream. @@ -162,5 +165,13 @@ namespace MediaBrowser.Controller.LiveTv /// <param name="cancellationToken">The cancellation token.</param> /// <returns>Task.</returns> 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); } } diff --git a/MediaBrowser.Controller/LiveTv/LiveTvProgram.cs b/MediaBrowser.Controller/LiveTv/LiveTvProgram.cs index abacc0c18..aceb32885 100644 --- a/MediaBrowser.Controller/LiveTv/LiveTvProgram.cs +++ b/MediaBrowser.Controller/LiveTv/LiveTvProgram.cs @@ -1,5 +1,6 @@ using MediaBrowser.Controller.Entities; using MediaBrowser.Model.LiveTv; +using System; 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() { return "Program"; diff --git a/MediaBrowser.Model/LiveTv/ProgramQuery.cs b/MediaBrowser.Model/LiveTv/ProgramQuery.cs index 36c06d4c0..a2a824994 100644 --- a/MediaBrowser.Model/LiveTv/ProgramQuery.cs +++ b/MediaBrowser.Model/LiveTv/ProgramQuery.cs @@ -32,4 +32,31 @@ namespace MediaBrowser.Model.LiveTv 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; } + } } diff --git a/MediaBrowser.Server.Implementations/LiveTv/LiveTvManager.cs b/MediaBrowser.Server.Implementations/LiveTv/LiveTvManager.cs index 17e17ab70..91766e0f8 100644 --- a/MediaBrowser.Server.Implementations/LiveTv/LiveTvManager.cs +++ b/MediaBrowser.Server.Implementations/LiveTv/LiveTvManager.cs @@ -32,6 +32,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv private readonly ILogger _logger; private readonly IItemRepository _itemRepo; private readonly IUserManager _userManager; + private readonly IUserDataManager _userDataManager; private readonly ILibraryManager _libraryManager; private readonly IMediaEncoder _mediaEncoder; @@ -54,6 +55,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv _userManager = userManager; _libraryManager = libraryManager; _mediaEncoder = mediaEncoder; + _userDataManager = userDataManager; _tvDtoService = new LiveTvDtoService(dtoService, userDataManager, imageProcessor, logger, _itemRepo); } @@ -428,7 +430,6 @@ namespace MediaBrowser.Server.Implementations.LiveTv } var returnArray = programs - .OrderBy(i => i.ProgramInfo.StartDate) .Select(i => { var channel = GetChannel(i); @@ -450,6 +451,138 @@ namespace MediaBrowser.Server.Implementations.LiveTv 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) { var timers = await ActiveService.GetTimersAsync(cancellationToken).ConfigureAwait(false); @@ -533,7 +666,10 @@ namespace MediaBrowser.Server.Implementations.LiveTv 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 programEntities = await Task.WhenAll(programTasks).ConfigureAwait(false); diff --git a/MediaBrowser.WebDashboard/ApiClient.js b/MediaBrowser.WebDashboard/ApiClient.js index fe0e5e541..b35341ebb 100644 --- a/MediaBrowser.WebDashboard/ApiClient.js +++ b/MediaBrowser.WebDashboard/ApiClient.js @@ -438,7 +438,7 @@ MediaBrowser.ApiClient = function ($, navigator, JSON, WebSocket, setTimeout, wi options = options || {}; - if (options.channelIds) { + if (options.channelIds && options.channelIds.length > 1800) { return self.ajax({ 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) { var url = self.getUrl("LiveTv/Recordings", options || {}); diff --git a/MediaBrowser.WebDashboard/packages.config b/MediaBrowser.WebDashboard/packages.config index 6c512e8bb..b28f5655a 100644 --- a/MediaBrowser.WebDashboard/packages.config +++ b/MediaBrowser.WebDashboard/packages.config @@ -1,4 +1,4 @@ <?xml version="1.0" encoding="utf-8"?> <packages> - <package id="MediaBrowser.ApiClient.Javascript" version="3.0.224" targetFramework="net45" /> + <package id="MediaBrowser.ApiClient.Javascript" version="3.0.226" targetFramework="net45" /> </packages>
\ No newline at end of file diff --git a/Nuget/MediaBrowser.Common.Internal.nuspec b/Nuget/MediaBrowser.Common.Internal.nuspec index 534957de6..9c011b3f4 100644 --- a/Nuget/MediaBrowser.Common.Internal.nuspec +++ b/Nuget/MediaBrowser.Common.Internal.nuspec @@ -2,7 +2,7 @@ <package xmlns="http://schemas.microsoft.com/packaging/2011/08/nuspec.xsd"> <metadata> <id>MediaBrowser.Common.Internal</id> - <version>3.0.298</version> + <version>3.0.299</version> <title>MediaBrowser.Common.Internal</title> <authors>Luke</authors> <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> <copyright>Copyright © Media Browser 2013</copyright> <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="SimpleInjector" version="2.4.0" /> <dependency id="sharpcompress" version="0.10.2" /> diff --git a/Nuget/MediaBrowser.Common.nuspec b/Nuget/MediaBrowser.Common.nuspec index e6792e1df..d0cd3a306 100644 --- a/Nuget/MediaBrowser.Common.nuspec +++ b/Nuget/MediaBrowser.Common.nuspec @@ -2,7 +2,7 @@ <package xmlns="http://schemas.microsoft.com/packaging/2011/08/nuspec.xsd"> <metadata> <id>MediaBrowser.Common</id> - <version>3.0.298</version> + <version>3.0.299</version> <title>MediaBrowser.Common</title> <authors>Media Browser Team</authors> <owners>ebr,Luke,scottisafool</owners> diff --git a/Nuget/MediaBrowser.Server.Core.nuspec b/Nuget/MediaBrowser.Server.Core.nuspec index db48a2891..cc15b8c4d 100644 --- a/Nuget/MediaBrowser.Server.Core.nuspec +++ b/Nuget/MediaBrowser.Server.Core.nuspec @@ -2,7 +2,7 @@ <package xmlns="http://schemas.microsoft.com/packaging/2010/07/nuspec.xsd"> <metadata> <id>MediaBrowser.Server.Core</id> - <version>3.0.298</version> + <version>3.0.299</version> <title>Media Browser.Server.Core</title> <authors>Media Browser Team</authors> <owners>ebr,Luke,scottisafool</owners> @@ -12,7 +12,7 @@ <description>Contains core components required to build plugins for Media Browser Server.</description> <copyright>Copyright © Media Browser 2013</copyright> <dependencies> - <dependency id="MediaBrowser.Common" version="3.0.298" /> + <dependency id="MediaBrowser.Common" version="3.0.299" /> </dependencies> </metadata> <files> |
