aboutsummaryrefslogtreecommitdiff
path: root/MediaBrowser.Server.Implementations
diff options
context:
space:
mode:
authorLuke Pulverenti <luke.pulverenti@gmail.com>2015-06-01 10:49:23 -0400
committerLuke Pulverenti <luke.pulverenti@gmail.com>2015-06-01 10:49:23 -0400
commitf2abd8ba39eefd5397eb3f0e327efbca8d8ecd0f (patch)
treeb2759d5a30620db61d324d00d5956d9bfc4e43e1 /MediaBrowser.Server.Implementations
parent68e64feafd1e5e91522938fa91217d3d9ce26e62 (diff)
update live tv database
Diffstat (limited to 'MediaBrowser.Server.Implementations')
-rw-r--r--MediaBrowser.Server.Implementations/IO/LibraryMonitor.cs2
-rw-r--r--MediaBrowser.Server.Implementations/Library/LibraryManager.cs13
-rw-r--r--MediaBrowser.Server.Implementations/LiveTv/LiveTvManager.cs377
-rw-r--r--MediaBrowser.Server.Implementations/LiveTv/ProgramImageProvider.cs4
-rw-r--r--MediaBrowser.Server.Implementations/Persistence/SqliteItemRepository.cs332
5 files changed, 477 insertions, 251 deletions
diff --git a/MediaBrowser.Server.Implementations/IO/LibraryMonitor.cs b/MediaBrowser.Server.Implementations/IO/LibraryMonitor.cs
index 491549d64..ef2888e4a 100644
--- a/MediaBrowser.Server.Implementations/IO/LibraryMonitor.cs
+++ b/MediaBrowser.Server.Implementations/IO/LibraryMonitor.cs
@@ -84,7 +84,7 @@ namespace MediaBrowser.Server.Implementations.IO
// This is an arbitraty amount of time, but delay it because file system writes often trigger events after RemoveTempIgnore has been called.
// Seeing long delays in some situations, especially over the network, sometimes up to 45 seconds
// But if we make this delay too high, we risk missing legitimate changes
- await Task.Delay(10000).ConfigureAwait(false);
+ await Task.Delay(15000).ConfigureAwait(false);
string val;
_tempIgnoredPaths.TryRemove(path, out val);
diff --git a/MediaBrowser.Server.Implementations/Library/LibraryManager.cs b/MediaBrowser.Server.Implementations/Library/LibraryManager.cs
index ee0bf354f..ed5dde4c5 100644
--- a/MediaBrowser.Server.Implementations/Library/LibraryManager.cs
+++ b/MediaBrowser.Server.Implementations/Library/LibraryManager.cs
@@ -16,6 +16,7 @@ using MediaBrowser.Controller.Sorting;
using MediaBrowser.Model.Configuration;
using MediaBrowser.Model.Entities;
using MediaBrowser.Model.Logging;
+using MediaBrowser.Model.Querying;
using MediaBrowser.Naming.Audio;
using MediaBrowser.Naming.Common;
using MediaBrowser.Naming.TV;
@@ -1209,6 +1210,18 @@ namespace MediaBrowser.Server.Implementations.Library
return item;
}
+ public QueryResult<BaseItem> GetItems(InternalItemsQuery query)
+ {
+ var result = ItemRepository.GetItemIdsList(query);
+
+ var items = result.Select(GetItemById).ToArray();
+
+ return new QueryResult<BaseItem>
+ {
+ Items = items
+ };
+ }
+
/// <summary>
/// Gets the intros.
/// </summary>
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
{
diff --git a/MediaBrowser.Server.Implementations/LiveTv/ProgramImageProvider.cs b/MediaBrowser.Server.Implementations/LiveTv/ProgramImageProvider.cs
index b01dddb94..134e24ef0 100644
--- a/MediaBrowser.Server.Implementations/LiveTv/ProgramImageProvider.cs
+++ b/MediaBrowser.Server.Implementations/LiveTv/ProgramImageProvider.cs
@@ -70,7 +70,9 @@ namespace MediaBrowser.Server.Implementations.LiveTv
{
try
{
- var response = await service.GetProgramImageAsync(liveTvItem.ExternalId, liveTvItem.ExternalChannelId, cancellationToken).ConfigureAwait(false);
+ var channel = _liveTvManager.GetInternalChannel(liveTvItem.ChannelId);
+
+ var response = await service.GetProgramImageAsync(liveTvItem.ExternalId, channel.ExternalId, cancellationToken).ConfigureAwait(false);
if (response != null)
{
diff --git a/MediaBrowser.Server.Implementations/Persistence/SqliteItemRepository.cs b/MediaBrowser.Server.Implementations/Persistence/SqliteItemRepository.cs
index c5a9db87b..19aca1cf9 100644
--- a/MediaBrowser.Server.Implementations/Persistence/SqliteItemRepository.cs
+++ b/MediaBrowser.Server.Implementations/Persistence/SqliteItemRepository.cs
@@ -1,12 +1,15 @@
using MediaBrowser.Common.Configuration;
using MediaBrowser.Controller.Entities;
+using MediaBrowser.Controller.LiveTv;
using MediaBrowser.Controller.Persistence;
using MediaBrowser.Model.Entities;
using MediaBrowser.Model.Logging;
+using MediaBrowser.Model.Querying;
using MediaBrowser.Model.Serialization;
using System;
using System.Collections.Generic;
using System.Data;
+using System.Globalization;
using System.IO;
using System.Linq;
using System.Threading;
@@ -126,6 +129,12 @@ namespace MediaBrowser.Server.Implementations.Persistence
_connection.RunQueries(queries, _logger);
+ _connection.AddColumn(_logger, "TypedBaseItems", "StartDate", "DATETIME");
+ _connection.AddColumn(_logger, "TypedBaseItems", "EndDate", "DATETIME");
+ _connection.AddColumn(_logger, "TypedBaseItems", "ChannelId", "Text");
+ _connection.AddColumn(_logger, "TypedBaseItems", "IsMovie", "BIT");
+ _connection.AddColumn(_logger, "TypedBaseItems", "IsSports", "BIT");
+
PrepareStatements();
_mediaStreamsRepository.Initialize();
@@ -143,10 +152,15 @@ namespace MediaBrowser.Server.Implementations.Persistence
private void PrepareStatements()
{
_saveItemCommand = _connection.CreateCommand();
- _saveItemCommand.CommandText = "replace into TypedBaseItems (guid, type, data) values (@1, @2, @3)";
+ _saveItemCommand.CommandText = "replace into TypedBaseItems (guid, type, data, StartDate, EndDate, ChannelId, IsMovie, IsSports) values (@1, @2, @3, @4, @5, @6, @7, @8)";
_saveItemCommand.Parameters.Add(_saveItemCommand, "@1");
_saveItemCommand.Parameters.Add(_saveItemCommand, "@2");
_saveItemCommand.Parameters.Add(_saveItemCommand, "@3");
+ _saveItemCommand.Parameters.Add(_saveItemCommand, "@4");
+ _saveItemCommand.Parameters.Add(_saveItemCommand, "@5");
+ _saveItemCommand.Parameters.Add(_saveItemCommand, "@6");
+ _saveItemCommand.Parameters.Add(_saveItemCommand, "@7");
+ _saveItemCommand.Parameters.Add(_saveItemCommand, "@8");
_deleteChildrenCommand = _connection.CreateCommand();
_deleteChildrenCommand.CommandText = "delete from ChildrenIds where ParentId=@ParentId";
@@ -155,7 +169,7 @@ namespace MediaBrowser.Server.Implementations.Persistence
_deleteItemCommand = _connection.CreateCommand();
_deleteItemCommand.CommandText = "delete from TypedBaseItems where guid=@Id";
_deleteItemCommand.Parameters.Add(_deleteItemCommand, "@Id");
-
+
_saveChildrenCommand = _connection.CreateCommand();
_saveChildrenCommand.CommandText = "replace into ChildrenIds (ParentId, ItemId) values (@ParentId, @ItemId)";
_saveChildrenCommand.Parameters.Add(_saveChildrenCommand, "@ParentId");
@@ -200,7 +214,7 @@ namespace MediaBrowser.Server.Implementations.Persistence
cancellationToken.ThrowIfCancellationRequested();
CheckDisposed();
-
+
await _writeLock.WaitAsync(cancellationToken).ConfigureAwait(false);
IDbTransaction transaction = null;
@@ -217,6 +231,31 @@ namespace MediaBrowser.Server.Implementations.Persistence
_saveItemCommand.GetParameter(1).Value = item.GetType().FullName;
_saveItemCommand.GetParameter(2).Value = _jsonSerializer.SerializeToBytes(item);
+ var hasStartDate = item as IHasStartDate;
+ if (hasStartDate != null)
+ {
+ _saveItemCommand.GetParameter(3).Value = hasStartDate.StartDate;
+ }
+ else
+ {
+ _saveItemCommand.GetParameter(3).Value = null;
+ }
+
+ _saveItemCommand.GetParameter(4).Value = item.EndDate;
+ _saveItemCommand.GetParameter(5).Value = item.ChannelId;
+
+ var hasProgramAttributes = item as IHasProgramAttributes;
+ if (hasProgramAttributes != null)
+ {
+ _saveItemCommand.GetParameter(6).Value = hasProgramAttributes.IsMovie;
+ _saveItemCommand.GetParameter(7).Value = hasProgramAttributes.IsSports;
+ }
+ else
+ {
+ _saveItemCommand.GetParameter(6).Value = null;
+ _saveItemCommand.GetParameter(7).Value = null;
+ }
+
_saveItemCommand.Transaction = transaction;
_saveItemCommand.ExecuteNonQuery();
@@ -254,7 +293,7 @@ namespace MediaBrowser.Server.Implementations.Persistence
_writeLock.Release();
}
}
-
+
/// <summary>
/// Internal retrieve from items or users table
/// </summary>
@@ -270,7 +309,7 @@ namespace MediaBrowser.Server.Implementations.Persistence
}
CheckDisposed();
-
+
using (var cmd = _connection.CreateCommand())
{
cmd.CommandText = "select type,data from TypedBaseItems where guid = @guid";
@@ -467,7 +506,7 @@ namespace MediaBrowser.Server.Implementations.Persistence
}
CheckDisposed();
-
+
using (var cmd = _connection.CreateCommand())
{
cmd.CommandText = "select ItemId from ChildrenIds where ParentId = @ParentId";
@@ -492,7 +531,7 @@ namespace MediaBrowser.Server.Implementations.Persistence
}
CheckDisposed();
-
+
using (var cmd = _connection.CreateCommand())
{
cmd.CommandText = "select type,data from TypedBaseItems where guid in (select ItemId from ChildrenIds where ParentId = @ParentId)";
@@ -544,6 +583,279 @@ namespace MediaBrowser.Server.Implementations.Persistence
}
}
+ public QueryResult<BaseItem> GetItems(InternalItemsQuery query)
+ {
+ if (query == null)
+ {
+ throw new ArgumentNullException("query");
+ }
+
+ CheckDisposed();
+
+ using (var cmd = _connection.CreateCommand())
+ {
+ cmd.CommandText = "select type,data from TypedBaseItems";
+
+ var whereClauses = GetWhereClauses(query, cmd, false);
+
+ var whereTextWithoutPaging = whereClauses.Count == 0 ?
+ string.Empty :
+ " where " + string.Join(" AND ", whereClauses.ToArray());
+
+ whereClauses = GetWhereClauses(query, cmd, true);
+
+ var whereText = whereClauses.Count == 0 ?
+ string.Empty :
+ " where " + string.Join(" AND ", whereClauses.ToArray());
+
+ cmd.CommandText += whereText;
+
+ if (query.Limit.HasValue)
+ {
+ cmd.CommandText += " LIMIT " + query.Limit.Value.ToString(CultureInfo.InvariantCulture);
+ }
+
+ cmd.CommandText += "; select count (guid) from TypedBaseItems" + whereTextWithoutPaging;
+
+ var list = new List<BaseItem>();
+ var count = 0;
+
+ using (var reader = cmd.ExecuteReader(CommandBehavior.SequentialAccess))
+ {
+ while (reader.Read())
+ {
+ list.Add(GetItem(reader));
+ }
+
+ if (reader.NextResult() && reader.Read())
+ {
+ count = reader.GetInt32(0);
+ }
+ }
+
+ return new QueryResult<BaseItem>()
+ {
+ Items = list.ToArray(),
+ TotalRecordCount = count
+ };
+ }
+ }
+
+ public List<Guid> GetItemIdsList(InternalItemsQuery query)
+ {
+ if (query == null)
+ {
+ throw new ArgumentNullException("query");
+ }
+
+ CheckDisposed();
+
+ using (var cmd = _connection.CreateCommand())
+ {
+ cmd.CommandText = "select guid from TypedBaseItems";
+
+ var whereClauses = GetWhereClauses(query, cmd, false);
+
+ whereClauses = GetWhereClauses(query, cmd, true);
+
+ var whereText = whereClauses.Count == 0 ?
+ string.Empty :
+ " where " + string.Join(" AND ", whereClauses.ToArray());
+
+ cmd.CommandText += whereText;
+
+ if (query.Limit.HasValue)
+ {
+ cmd.CommandText += " LIMIT " + query.Limit.Value.ToString(CultureInfo.InvariantCulture);
+ }
+
+ var list = new List<Guid>();
+
+ _logger.Debug(cmd.CommandText);
+
+ using (var reader = cmd.ExecuteReader(CommandBehavior.SequentialAccess))
+ {
+ while (reader.Read())
+ {
+ list.Add(reader.GetGuid(0));
+ }
+ }
+
+ return list;
+ }
+ }
+
+ public QueryResult<Guid> GetItemIds(InternalItemsQuery query)
+ {
+ if (query == null)
+ {
+ throw new ArgumentNullException("query");
+ }
+
+ CheckDisposed();
+
+ using (var cmd = _connection.CreateCommand())
+ {
+ cmd.CommandText = "select guid from TypedBaseItems";
+
+ var whereClauses = GetWhereClauses(query, cmd, false);
+
+ var whereTextWithoutPaging = whereClauses.Count == 0 ?
+ string.Empty :
+ " where " + string.Join(" AND ", whereClauses.ToArray());
+
+ whereClauses = GetWhereClauses(query, cmd, true);
+
+ var whereText = whereClauses.Count == 0 ?
+ string.Empty :
+ " where " + string.Join(" AND ", whereClauses.ToArray());
+
+ cmd.CommandText += whereText;
+
+ if (query.Limit.HasValue)
+ {
+ cmd.CommandText += " LIMIT " + query.Limit.Value.ToString(CultureInfo.InvariantCulture);
+ }
+
+ cmd.CommandText += "; select count (guid) from TypedBaseItems" + whereTextWithoutPaging;
+
+ var list = new List<Guid>();
+ var count = 0;
+
+ _logger.Debug(cmd.CommandText);
+
+ using (var reader = cmd.ExecuteReader(CommandBehavior.SequentialAccess))
+ {
+ while (reader.Read())
+ {
+ list.Add(reader.GetGuid(0));
+ }
+
+ if (reader.NextResult() && reader.Read())
+ {
+ count = reader.GetInt32(0);
+ }
+ }
+
+ return new QueryResult<Guid>()
+ {
+ Items = list.ToArray(),
+ TotalRecordCount = count
+ };
+ }
+ }
+
+ private List<string> GetWhereClauses(InternalItemsQuery query, IDbCommand cmd, bool addPaging)
+ {
+ var whereClauses = new List<string>();
+
+ if (query.IsMovie.HasValue)
+ {
+ whereClauses.Add("IsMovie=@IsMovie");
+ cmd.Parameters.Add(cmd, "@IsMovie", DbType.Boolean).Value = query.IsMovie;
+ }
+ if (query.IsSports.HasValue)
+ {
+ whereClauses.Add("IsSports=@IsSports");
+ cmd.Parameters.Add(cmd, "@IsSports", DbType.Boolean).Value = query.IsSports;
+ }
+ if (query.IncludeItemTypes.Length == 1)
+ {
+ whereClauses.Add("type=@type");
+ cmd.Parameters.Add(cmd, "@type", DbType.String).Value = MapIncludeItemType(query.IncludeItemTypes[0]);
+ }
+ if (query.IncludeItemTypes.Length > 1)
+ {
+ var inClause = string.Join(",", query.IncludeItemTypes.Select(i => "'" + MapIncludeItemType(i) + "'").ToArray());
+ whereClauses.Add(string.Format("type in ({0})", inClause));
+ }
+ if (query.ChannelIds.Length == 1)
+ {
+ whereClauses.Add("ChannelId=@ChannelId");
+ cmd.Parameters.Add(cmd, "@ChannelId", DbType.String).Value = query.ChannelIds[0];
+ }
+ if (query.ChannelIds.Length > 1)
+ {
+ var inClause = string.Join(",", query.ChannelIds.Select(i => "'" + i + "'").ToArray());
+ whereClauses.Add(string.Format("ChannelId in ({0})", inClause));
+ }
+
+ if (query.MinEndDate.HasValue)
+ {
+ whereClauses.Add("EndDate>=@MinEndDate");
+ cmd.Parameters.Add(cmd, "@MinEndDate", DbType.Date).Value = query.MinEndDate.Value;
+ }
+
+ if (query.MaxEndDate.HasValue)
+ {
+ whereClauses.Add("EndDate<=@MaxEndDate");
+ cmd.Parameters.Add(cmd, "@MaxEndDate", DbType.Date).Value = query.MaxEndDate.Value;
+ }
+
+ if (query.MinStartDate.HasValue)
+ {
+ whereClauses.Add("StartDate>=@MinStartDate");
+ cmd.Parameters.Add(cmd, "@MinStartDate", DbType.Date).Value = query.MinStartDate.Value;
+ }
+
+ if (query.MaxStartDate.HasValue)
+ {
+ whereClauses.Add("StartDate<=@MaxStartDate");
+ cmd.Parameters.Add(cmd, "@MaxStartDate", DbType.Date).Value = query.MaxStartDate.Value;
+ }
+
+ if (query.IsAiring.HasValue)
+ {
+ if (query.IsAiring.Value)
+ {
+ whereClauses.Add("StartDate<=@MaxStartDate");
+ cmd.Parameters.Add(cmd, "@MaxStartDate", DbType.Date).Value = DateTime.UtcNow;
+
+ whereClauses.Add("EndDate>=@MinEndDate");
+ cmd.Parameters.Add(cmd, "@MinEndDate", DbType.Date).Value = DateTime.UtcNow;
+ }
+ else
+ {
+ whereClauses.Add("(StartDate>@IsAiringDate OR EndDate < @IsAiringDate)");
+ cmd.Parameters.Add(cmd, "@IsAiringDate", DbType.Date).Value = DateTime.UtcNow;
+ }
+ }
+
+ if (addPaging)
+ {
+ if (query.StartIndex.HasValue && query.StartIndex.Value > 0)
+ {
+ var pagingWhereText = whereClauses.Count == 0 ?
+ string.Empty :
+ " where " + string.Join(" AND ", whereClauses.ToArray());
+
+ whereClauses.Add(string.Format("Id NOT IN (SELECT Id FROM TypedBaseItems {0} ORDER BY DateCreated DESC LIMIT {1})",
+ pagingWhereText,
+ query.StartIndex.Value.ToString(CultureInfo.InvariantCulture)));
+ }
+ }
+
+ return whereClauses;
+ }
+
+ // Not crazy about having this all the way down here, but at least it's in one place
+ readonly Dictionary<string, string> _types = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase)
+ {
+ {typeof(LiveTvProgram).Name, typeof(LiveTvProgram).FullName},
+ {typeof(LiveTvChannel).Name, typeof(LiveTvChannel).FullName}
+ };
+
+ private string MapIncludeItemType(string value)
+ {
+ string result;
+ if (_types.TryGetValue(value, out result))
+ {
+ return result;
+ }
+
+ return value;
+ }
+
public IEnumerable<Guid> GetItemIdsOfType(Type type)
{
if (type == null)
@@ -577,7 +889,7 @@ namespace MediaBrowser.Server.Implementations.Persistence
}
CheckDisposed();
-
+
await _writeLock.WaitAsync(cancellationToken).ConfigureAwait(false);
IDbTransaction transaction = null;
@@ -595,7 +907,7 @@ namespace MediaBrowser.Server.Implementations.Persistence
_deleteItemCommand.GetParameter(0).Value = id;
_deleteItemCommand.Transaction = transaction;
_deleteItemCommand.ExecuteNonQuery();
-
+
transaction.Commit();
}
catch (OperationCanceledException)
@@ -642,7 +954,7 @@ namespace MediaBrowser.Server.Implementations.Persistence
}
CheckDisposed();
-
+
await _writeLock.WaitAsync(cancellationToken).ConfigureAwait(false);
IDbTransaction transaction = null;