diff options
Diffstat (limited to 'MediaBrowser.Server.Implementations/LiveTv/LiveTvManager.cs')
| -rw-r--r-- | MediaBrowser.Server.Implementations/LiveTv/LiveTvManager.cs | 377 |
1 files changed, 138 insertions, 239 deletions
diff --git a/MediaBrowser.Server.Implementations/LiveTv/LiveTvManager.cs b/MediaBrowser.Server.Implementations/LiveTv/LiveTvManager.cs index dbae6d03e..47e862b9f 100644 --- a/MediaBrowser.Server.Implementations/LiveTv/LiveTvManager.cs +++ b/MediaBrowser.Server.Implementations/LiveTv/LiveTvManager.cs @@ -17,7 +17,6 @@ using MediaBrowser.Model.Dto; using MediaBrowser.Model.Entities; using MediaBrowser.Model.LiveTv; using MediaBrowser.Model.Logging; -using MediaBrowser.Model.MediaInfo; using MediaBrowser.Model.Querying; using MediaBrowser.Model.Serialization; using System; @@ -54,10 +53,6 @@ namespace MediaBrowser.Server.Implementations.LiveTv private readonly ConcurrentDictionary<string, LiveStreamData> _openStreams = new ConcurrentDictionary<string, LiveStreamData>(); - private List<Guid> _channelIdList = new List<Guid>(); - private Dictionary<Guid, LiveTvProgram> _programs; - private readonly ConcurrentDictionary<Guid, bool> _refreshedPrograms = new ConcurrentDictionary<Guid, bool>(); - public LiveTvManager(IApplicationHost appHost, IServerConfigurationManager config, ILogger logger, IItemRepository itemRepo, IImageProcessor imageProcessor, IUserDataManager userDataManager, IDtoService dtoService, IUserManager userManager, ILibraryManager libraryManager, ITaskManager taskManager, ILocalizationManager localization, IJsonSerializer jsonSerializer, IProviderManager providerManager) { _config = config; @@ -108,44 +103,15 @@ namespace MediaBrowser.Server.Implementations.LiveTv _taskManager.CancelIfRunningAndQueue<RefreshChannelsScheduledTask>(); } - private readonly object _programsDataLock = new object(); - private Dictionary<Guid, LiveTvProgram> GetProgramsDictionary() - { - if (_programs == null) - { - lock (_programsDataLock) - { - if (_programs == null) - { - var dict = new Dictionary<Guid, LiveTvProgram>(); - - foreach (var item in _itemRepo.GetItemsOfType(typeof(LiveTvProgram)) - .Cast<LiveTvProgram>() - .ToList()) - { - dict[item.Id] = item; - } - - _programs = dict; - } - } - } - - return _programs; - } - - private IEnumerable<LiveTvProgram> GetPrograms() - { - return GetProgramsDictionary().Values; - } - public async Task<QueryResult<LiveTvChannel>> GetInternalChannels(LiveTvChannelQuery query, CancellationToken cancellationToken) { var user = string.IsNullOrEmpty(query.UserId) ? null : _userManager.GetUserById(query.UserId); - var channels = _channelIdList.Select(_libraryManager.GetItemById) - .Where(i => i != null) - .OfType<LiveTvChannel>(); + var channels = _libraryManager.GetItems(new InternalItemsQuery + { + IncludeItemTypes = new[] { typeof(LiveTvChannel).Name } + + }).Items.Cast<LiveTvChannel>(); if (user != null) { @@ -258,9 +224,20 @@ namespace MediaBrowser.Server.Implementations.LiveTv var returnList = new List<ChannelInfoDto>(); + var now = DateTime.UtcNow; + + var programs = _libraryManager.GetItems(new InternalItemsQuery + { + IncludeItemTypes = new[] { typeof(LiveTvProgram).Name }, + MaxStartDate = now, + MinEndDate = now + + }).Items.Cast<LiveTvProgram>().OrderBy(i => i.StartDate).ToList(); + foreach (var channel in internalResult.Items) { - var currentProgram = GetCurrentProgram(channel.ExternalId); + 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)); } @@ -286,34 +263,12 @@ namespace MediaBrowser.Server.Implementations.LiveTv internal LiveTvProgram GetInternalProgram(string id) { - var guid = new Guid(id); - - LiveTvProgram obj = null; - - GetProgramsDictionary().TryGetValue(guid, out obj); - - if (obj != null) - { - RefreshIfNeeded(obj); - } - return obj; - } - - private void RefreshIfNeeded(LiveTvProgram program) - { - if (!_refreshedPrograms.ContainsKey(program.Id)) - { - _refreshedPrograms.TryAdd(program.Id, true); - _providerManager.QueueRefresh(program.Id, new MetadataRefreshOptions()); - } + return _libraryManager.GetItemById(id) as LiveTvProgram; } - private void RefreshIfNeeded(IEnumerable<LiveTvProgram> programs) + internal LiveTvProgram GetInternalProgram(Guid id) { - foreach (var program in programs) - { - RefreshIfNeeded(program); - } + return _libraryManager.GetItemById(id) as LiveTvProgram; } public async Task<ILiveTvRecording> GetInternalRecording(string id, CancellationToken cancellationToken) @@ -598,14 +553,16 @@ namespace MediaBrowser.Server.Implementations.LiveTv return item; } - private async Task<LiveTvProgram> GetProgram(ProgramInfo info, ChannelType channelType, string serviceName, CancellationToken cancellationToken) + private async Task<LiveTvProgram> GetProgram(ProgramInfo info, string channelId, ChannelType channelType, string serviceName, CancellationToken cancellationToken) { var id = _tvDtoService.GetInternalProgramId(serviceName, info.Id); var item = _libraryManager.GetItemById(id) as LiveTvProgram; + var isNew = false; if (item == null) { + isNew = true; item = new LiveTvProgram { Name = info.Name, @@ -619,8 +576,8 @@ namespace MediaBrowser.Server.Implementations.LiveTv item.ServiceName = serviceName; item.Audio = info.Audio; - item.ExternalChannelId = info.ChannelId; - item.CommunityRating = info.CommunityRating; + item.ChannelId = channelId; + item.CommunityRating = item.CommunityRating ?? info.CommunityRating; item.EndDate = info.EndDate; item.EpisodeTitle = info.EpisodeTitle; item.ExternalId = info.Id; @@ -636,8 +593,8 @@ namespace MediaBrowser.Server.Implementations.LiveTv item.IsSeries = info.IsSeries; item.IsSports = info.IsSports; item.Name = info.Name; - item.OfficialRating = info.OfficialRating; - item.Overview = info.Overview; + item.OfficialRating = item.OfficialRating ?? info.OfficialRating; + item.Overview = item.Overview ?? info.Overview; item.OriginalAirDate = info.OriginalAirDate; item.ProviderImagePath = info.ImagePath; item.ProviderImageUrl = info.ImageUrl; @@ -647,7 +604,16 @@ namespace MediaBrowser.Server.Implementations.LiveTv item.ProductionYear = info.ProductionYear; item.PremiereDate = item.PremiereDate ?? info.OriginalAirDate; - await item.UpdateToRepository(ItemUpdateType.MetadataImport, cancellationToken).ConfigureAwait(false); + if (isNew) + { + await _libraryManager.CreateItem(item, cancellationToken).ConfigureAwait(false); + } + else + { + await _libraryManager.UpdateItem(item, ItemUpdateType.MetadataImport, cancellationToken).ConfigureAwait(false); + } + + _providerManager.QueueRefresh(item.Id, new MetadataRefreshOptions()); return item; } @@ -721,17 +687,6 @@ namespace MediaBrowser.Server.Implementations.LiveTv return recording; } - private LiveTvChannel GetChannel(LiveTvProgram program) - { - var programChannelId = program.ExternalChannelId; - - if (string.IsNullOrWhiteSpace(programChannelId)) return null; - - var internalProgramChannelId = _tvDtoService.GetInternalChannelId(program.ServiceName, programChannelId); - - return GetInternalChannel(internalProgramChannelId); - } - public async Task<BaseItemDto> GetProgram(string id, CancellationToken cancellationToken, User user = null) { var program = GetInternalProgram(id); @@ -745,64 +700,31 @@ namespace MediaBrowser.Server.Implementations.LiveTv public async Task<QueryResult<BaseItemDto>> GetPrograms(ProgramQuery query, CancellationToken cancellationToken) { - IEnumerable<LiveTvProgram> programs = GetPrograms(); - - if (query.MinEndDate.HasValue) + var internalQuery = new InternalItemsQuery { - var val = query.MinEndDate.Value; - - programs = programs.Where(i => i.EndDate.HasValue && i.EndDate.Value >= val); - } - - if (query.MinStartDate.HasValue) - { - var val = query.MinStartDate.Value; - - programs = programs.Where(i => i.StartDate >= val); - } - - if (query.MaxEndDate.HasValue) - { - var val = query.MaxEndDate.Value; - - programs = programs.Where(i => i.EndDate.HasValue && i.EndDate.Value <= val); - } - - if (query.MaxStartDate.HasValue) - { - var val = query.MaxStartDate.Value; - - programs = programs.Where(i => i.StartDate <= val); - } + IncludeItemTypes = new[] { typeof(LiveTvProgram).Name }, + MinEndDate = query.MinEndDate, + MinStartDate = query.MinStartDate, + MaxEndDate = query.MaxEndDate, + MaxStartDate = query.MaxStartDate, + ChannelIds = query.ChannelIds, + IsMovie = query.IsMovie, + IsSports = query.IsSports + }; if (query.HasAired.HasValue) { - var val = query.HasAired.Value; - programs = programs.Where(i => i.HasAired == val); - } - - if (query.ChannelIds.Length > 0) - { - var guids = query.ChannelIds.Select(i => new Guid(i)).ToList(); - - programs = programs.Where(i => + if (query.HasAired.Value) { - var programChannelId = i.ExternalChannelId; - - var service = GetService(i); - var internalProgramChannelId = _tvDtoService.GetInternalChannelId(service.Name, programChannelId); - - return guids.Contains(internalProgramChannelId); - }); + internalQuery.MaxEndDate = DateTime.UtcNow; + } + else + { + internalQuery.MinEndDate = DateTime.UtcNow; + } } - var user = string.IsNullOrEmpty(query.UserId) ? null : _userManager.GetUserById(query.UserId); - if (user != null) - { - // Avoid implicitly captured closure - var currentUser = user; - programs = programs.Where(i => i.IsVisible(currentUser)); - } + IEnumerable<LiveTvProgram> programs = _libraryManager.GetItems(internalQuery).Items.Cast<LiveTvProgram>(); // Apply genre filter if (query.Genres.Length > 0) @@ -810,14 +732,12 @@ namespace MediaBrowser.Server.Implementations.LiveTv programs = programs.Where(p => p.Genres.Any(g => query.Genres.Contains(g, StringComparer.OrdinalIgnoreCase))); } - if (query.IsMovie.HasValue) - { - programs = programs.Where(p => p.IsMovie == query.IsMovie); - } - - if (query.IsSports.HasValue) + var user = string.IsNullOrEmpty(query.UserId) ? null : _userManager.GetUserById(query.UserId); + if (user != null) { - programs = programs.Where(p => p.IsSports == query.IsSports); + // Avoid implicitly captured closure + var currentUser = user; + programs = programs.Where(i => i.IsVisible(currentUser)); } programs = _libraryManager.Sort(programs, user, query.SortBy, query.SortOrder ?? SortOrder.Ascending) @@ -840,8 +760,6 @@ namespace MediaBrowser.Server.Implementations.LiveTv .Select(i => _dtoService.GetBaseItemDto(i, new DtoOptions(), user)) .ToArray(); - RefreshIfNeeded(programList); - await AddRecordingInfo(returnArray, cancellationToken).ConfigureAwait(false); var result = new QueryResult<BaseItemDto> @@ -855,35 +773,33 @@ namespace MediaBrowser.Server.Implementations.LiveTv public async Task<QueryResult<LiveTvProgram>> GetRecommendedProgramsInternal(RecommendedProgramQuery query, CancellationToken cancellationToken) { - IEnumerable<LiveTvProgram> programs = GetPrograms(); - - var user = _userManager.GetUserById(query.UserId); - - // Avoid implicitly captured closure - var currentUser = user; - programs = programs.Where(i => i.IsVisible(currentUser)); - - if (query.IsAiring.HasValue) + var internalQuery = new InternalItemsQuery { - var val = query.IsAiring.Value; - programs = programs.Where(i => i.IsAiring == val); - } + IncludeItemTypes = new[] { typeof(LiveTvProgram).Name }, + IsAiring = query.IsAiring, + IsMovie = query.IsMovie, + IsSports = query.IsSports + }; if (query.HasAired.HasValue) { - var val = query.HasAired.Value; - programs = programs.Where(i => i.HasAired == val); + if (query.HasAired.Value) + { + internalQuery.MaxEndDate = DateTime.UtcNow; + } + else + { + internalQuery.MinEndDate = DateTime.UtcNow; + } } - if (query.IsMovie.HasValue) - { - programs = programs.Where(p => p.IsMovie == query.IsMovie.Value); - } + IEnumerable<LiveTvProgram> programs = _libraryManager.GetItems(internalQuery).Items.Cast<LiveTvProgram>(); - if (query.IsSports.HasValue) - { - programs = programs.Where(p => p.IsSports == query.IsSports.Value); - } + var user = _userManager.GetUserById(query.UserId); + + // Avoid implicitly captured closure + var currentUser = user; + programs = programs.Where(i => i.IsVisible(currentUser)); var programList = programs.ToList(); @@ -904,8 +820,6 @@ namespace MediaBrowser.Server.Implementations.LiveTv programList = programs.ToList(); - RefreshIfNeeded(programList); - var returnArray = programList.ToArray(); var result = new QueryResult<LiveTvProgram> @@ -952,8 +866,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv score++; } - var internalChannelId = _tvDtoService.GetInternalChannelId(program.ServiceName, program.ExternalChannelId); - var channel = GetInternalChannel(internalChannelId); + var channel = GetInternalChannel(program.ChannelId); var channelUserdata = _userDataManager.GetUserData(userId, channel.GetUserDataKey()); @@ -1048,17 +961,9 @@ namespace MediaBrowser.Server.Implementations.LiveTv } } - internal async Task RefreshChannels(IProgress<double> progress, CancellationToken cancellationToken) + internal Task RefreshChannels(IProgress<double> progress, CancellationToken cancellationToken) { - var innerProgress = new ActionableProgress<double>(); - innerProgress.RegisterAction(p => progress.Report(p * .9)); - await RefreshChannelsInternal(innerProgress, cancellationToken).ConfigureAwait(false); - - innerProgress = new ActionableProgress<double>(); - innerProgress.RegisterAction(p => progress.Report(90 + (p * .1))); - await CleanDatabaseInternal(progress, cancellationToken).ConfigureAwait(false); - - RefreshIfNeeded(GetPrograms().ToList()); + return RefreshChannelsInternal(progress, cancellationToken); } private async Task RefreshChannelsInternal(IProgress<double> progress, CancellationToken cancellationToken) @@ -1068,6 +973,9 @@ namespace MediaBrowser.Server.Implementations.LiveTv ? 0 : 1 / _services.Count; + var newChannelIdList = new List<Guid>(); + var newProgramIdList = new List<Guid>(); + foreach (var service in _services) { cancellationToken.ThrowIfCancellationRequested(); @@ -1077,7 +985,10 @@ namespace MediaBrowser.Server.Implementations.LiveTv var innerProgress = new ActionableProgress<double>(); innerProgress.RegisterAction(p => progress.Report(p * progressPerService)); - await RefreshChannelsInternal(service, innerProgress, cancellationToken).ConfigureAwait(false); + var idList = await RefreshChannelsInternal(service, innerProgress, cancellationToken).ConfigureAwait(false); + + newChannelIdList.AddRange(idList.Item1); + newProgramIdList.AddRange(idList.Item2); } catch (OperationCanceledException) { @@ -1095,10 +1006,18 @@ namespace MediaBrowser.Server.Implementations.LiveTv progress.Report(100 * percent); } + await CleanDatabaseInternal(newChannelIdList, typeof(LiveTvChannel).Name, progress, cancellationToken).ConfigureAwait(false); + await CleanDatabaseInternal(newProgramIdList, typeof(LiveTvProgram).Name, progress, cancellationToken).ConfigureAwait(false); + + // Load these now which will prefetch metadata + var dtoOptions = new DtoOptions(); + dtoOptions.Fields.Remove(ItemFields.SyncInfo); + await GetRecordings(new RecordingQuery(), dtoOptions, cancellationToken).ConfigureAwait(false); + progress.Report(100); } - private async Task RefreshChannelsInternal(ILiveTvService service, IProgress<double> progress, CancellationToken cancellationToken) + private async Task<Tuple<List<Guid>,List<Guid>>> RefreshChannelsInternal(ILiveTvService service, IProgress<double> progress, CancellationToken cancellationToken) { progress.Report(10); @@ -1137,23 +1056,21 @@ namespace MediaBrowser.Server.Implementations.LiveTv progress.Report(5 * percent + 10); } - _channelIdList = list.Select(i => i.Id).ToList(); progress.Report(15); numComplete = 0; - var programs = new List<LiveTvProgram>(); + var programs = new List<Guid>(); + var channels = new List<Guid>(); var guideDays = GetGuideDays(list.Count); cancellationToken.ThrowIfCancellationRequested(); - foreach (var item in list) + foreach (var currentChannel in list) { + channels.Add(currentChannel.Id); cancellationToken.ThrowIfCancellationRequested(); - // Avoid implicitly captured closure - var currentChannel = item; - try { var start = DateTime.UtcNow.AddHours(-1); @@ -1161,9 +1078,12 @@ namespace MediaBrowser.Server.Implementations.LiveTv var channelPrograms = await service.GetProgramsAsync(currentChannel.ExternalId, start, end, cancellationToken).ConfigureAwait(false); + var channelId = currentChannel.Id.ToString("N"); + foreach (var program in channelPrograms) { - programs.Add(await GetProgram(program, currentChannel.ChannelType, service.Name, cancellationToken).ConfigureAwait(false)); + var programItem = await GetProgram(program, channelId, currentChannel.ChannelType, service.Name, cancellationToken).ConfigureAwait(false); + programs.Add(programItem.Id); } } catch (OperationCanceledException) @@ -1181,44 +1101,32 @@ namespace MediaBrowser.Server.Implementations.LiveTv progress.Report(80 * percent + 10); } - - lock (_programsDataLock) - { - _programs = programs.ToDictionary(i => i.Id); - } - - _refreshedPrograms.Clear(); - progress.Report(90); - - // Load these now which will prefetch metadata - var dtoOptions = new DtoOptions(); - dtoOptions.Fields.Remove(ItemFields.SyncInfo); - await GetRecordings(new RecordingQuery(), dtoOptions, cancellationToken).ConfigureAwait(false); progress.Report(100); - } - private Task CleanDatabaseInternal(IProgress<double> progress, CancellationToken cancellationToken) - { - return DeleteOldPrograms(GetProgramsDictionary().Keys.ToList(), progress, cancellationToken); + return new Tuple<List<Guid>,List<Guid>>(channels, programs); } - private async Task DeleteOldPrograms(List<Guid> currentIdList, IProgress<double> progress, CancellationToken cancellationToken) + private async Task CleanDatabaseInternal(List<Guid> currentIdList, string typeName, IProgress<double> progress, CancellationToken cancellationToken) { - var list = _itemRepo.GetItemIdsOfType(typeof(LiveTvProgram)).ToList(); + var list = _itemRepo.GetItemIds(new InternalItemsQuery + { + IncludeItemTypes = new[] { typeName } + + }).Items.ToList(); var numComplete = 0; - foreach (var programId in list) + foreach (var itemId in list) { cancellationToken.ThrowIfCancellationRequested(); - if (!currentIdList.Contains(programId)) + if (!currentIdList.Contains(itemId)) { - var program = _libraryManager.GetItemById(programId); + var item = _libraryManager.GetItemById(itemId); - if (program != null) + if (item != null) { - await _libraryManager.DeleteItem(program).ConfigureAwait(false); + await _libraryManager.DeleteItem(item).ConfigureAwait(false); } } @@ -1358,11 +1266,11 @@ namespace MediaBrowser.Server.Implementations.LiveTv var program = (LiveTvProgram)item; var service = GetService(program); - var channel = string.IsNullOrEmpty(program.ExternalChannelId) ? null : GetInternalChannel(_tvDtoService.GetInternalChannelId(service.Name, program.ExternalChannelId)); + var channel = GetInternalChannel(program.ChannelId); dto.Id = _tvDtoService.GetInternalProgramId(service.Name, program.ExternalId).ToString("N"); - dto.ChannelId = _tvDtoService.GetInternalChannelId(service.Name, program.ExternalChannelId).ToString("N"); + dto.ChannelId = channel.Id.ToString("N"); dto.StartDate = program.StartDate; dto.IsRepeat = program.IsRepeat; @@ -1676,29 +1584,25 @@ namespace MediaBrowser.Server.Implementations.LiveTv { var channel = GetInternalChannel(id); - var currentProgram = GetCurrentProgram(channel.ExternalId); - - var dto = _tvDtoService.GetChannelInfoDto(channel, currentProgram, user); + var now = DateTime.UtcNow; - return dto; - } + var programs = _libraryManager.GetItems(new InternalItemsQuery + { + IncludeItemTypes = new[] { typeof(LiveTvProgram).Name }, + ChannelIds = new[] { id }, + MaxStartDate = now, + MinEndDate = now, + Limit = 1 - private LiveTvProgram GetCurrentProgram(string externalChannelId) - { - var now = DateTime.UtcNow; + }).Items.Cast<LiveTvProgram>(); - var program = GetPrograms() - .Where(i => string.Equals(externalChannelId, i.ExternalChannelId, StringComparison.OrdinalIgnoreCase)) + var currentProgram = programs .OrderBy(i => i.StartDate) - .SkipWhile(i => now >= (i.EndDate ?? DateTime.MinValue)) .FirstOrDefault(); - if (program != null) - { - RefreshIfNeeded(program); - } + var dto = _tvDtoService.GetChannelInfoDto(channel, currentProgram, user); - return program; + return dto; } private async Task<Tuple<SeriesTimerInfo, ILiveTvService>> GetNewTimerDefaultsInternal(CancellationToken cancellationToken, LiveTvProgram program = null) @@ -1711,10 +1615,12 @@ namespace MediaBrowser.Server.Implementations.LiveTv if (program != null) { + var channel = GetInternalChannel(program.ChannelId); + programInfo = new ProgramInfo { Audio = program.Audio, - ChannelId = program.ExternalChannelId, + ChannelId = channel.ExternalId, CommunityRating = program.CommunityRating, EndDate = program.EndDate ?? DateTime.MinValue, EpisodeTitle = program.EpisodeTitle, @@ -1990,15 +1896,8 @@ namespace MediaBrowser.Server.Implementations.LiveTv public GuideInfo GetGuideInfo() { - var programs = GetPrograms().OrderBy(i => i.StartDate).ToList(); - - var startDate = programs.Count == 0 ? - DateTime.MinValue : - programs[0].StartDate; - - var endDate = programs.Count == 0 ? - DateTime.MinValue : - programs[programs.Count - 1].StartDate; + var startDate = DateTime.UtcNow; + var endDate = startDate.AddDays(14); return new GuideInfo { |
