update live tv database

This commit is contained in:
Luke Pulverenti 2015-06-01 10:49:23 -04:00
parent 68e64feafd
commit f2abd8ba39
20 changed files with 587 additions and 303 deletions

View File

@ -340,7 +340,7 @@ namespace MediaBrowser.Api
// We can really reduce the timeout for apps that are using the newer api
if (!string.IsNullOrWhiteSpace(job.PlaySessionId))
{
timerDuration = 60000;
timerDuration = 120000;
}
}

View File

@ -879,7 +879,7 @@ namespace MediaBrowser.Api.Playback.Hls
if (!EnableSplitTranscoding(state))
{
args += " -copyts";
//args += " -copyts";
}
return args;
@ -910,12 +910,12 @@ namespace MediaBrowser.Api.Playback.Hls
//toTimeParam = " -to " + MediaEncoder.GetTimeParameter(endTime);
toTimeParam = " -t " + MediaEncoder.GetTimeParameter(TimeSpan.FromSeconds(durationSeconds).Ticks);
}
}
if (state.IsOutputVideo && !string.Equals(state.OutputVideoCodec, "copy", StringComparison.OrdinalIgnoreCase) && (state.Request.StartTimeTicks ?? 0) > 0)
{
timestampOffsetParam = " -output_ts_offset " + MediaEncoder.GetTimeParameter(state.Request.StartTimeTicks ?? 0).ToString(CultureInfo.InvariantCulture);
}
}
var mapArgs = state.IsOutputVideo ? GetMapArgs(state) : string.Empty;
@ -959,6 +959,7 @@ namespace MediaBrowser.Api.Playback.Hls
private bool EnableSplitTranscoding(StreamState state)
{
return false;
if (string.Equals(Request.QueryString["EnableSplitTranscoding"], "false", StringComparison.OrdinalIgnoreCase))
{
return false;

View File

@ -42,7 +42,14 @@ namespace MediaBrowser.Api.Playback
var options = GetOptions();
if (options.EnableThrottling && IsThrottleAllowed(_job, options.ThrottleThresholdInSeconds))
var threshold = options.ThrottleThresholdInSeconds;
if (!options.EnableThrottling)
{
threshold *= 2;
}
if (IsThrottleAllowed(_job, threshold))
{
PauseTranscoding();
}
@ -56,7 +63,7 @@ namespace MediaBrowser.Api.Playback
{
if (!_isPaused)
{
_logger.Debug("Sending pause command to ffmpeg");
//_logger.Debug("Sending pause command to ffmpeg");
try
{
@ -74,7 +81,7 @@ namespace MediaBrowser.Api.Playback
{
if (_isPaused)
{
_logger.Debug("Sending unpause command to ffmpeg");
//_logger.Debug("Sending unpause command to ffmpeg");
try
{

View File

@ -15,7 +15,6 @@ namespace MediaBrowser.Controller.Channels
{
public string ExternalId { get; set; }
public string ChannelId { get; set; }
public string DataVersion { get; set; }
public ChannelItemType ChannelItemType { get; set; }

View File

@ -12,7 +12,6 @@ namespace MediaBrowser.Controller.Channels
{
public string ExternalId { get; set; }
public string ChannelId { get; set; }
public string DataVersion { get; set; }
public ChannelItemType ChannelItemType { get; set; }

View File

@ -16,7 +16,6 @@ namespace MediaBrowser.Controller.Channels
{
public string ExternalId { get; set; }
public string ChannelId { get; set; }
public string DataVersion { get; set; }
public ChannelItemType ChannelItemType { get; set; }

View File

@ -59,6 +59,12 @@ namespace MediaBrowser.Controller.Entities
public List<ItemImageInfo> ImageInfos { get; set; }
/// <summary>
/// Gets or sets the channel identifier.
/// </summary>
/// <value>The channel identifier.</value>
public string ChannelId { get; set; }
[IgnoreDataMember]
public virtual bool SupportsAddingToPlaylist
{

View File

@ -0,0 +1,9 @@

namespace MediaBrowser.Controller.Entities
{
public interface IHasProgramAttributes
{
bool IsMovie { get; set; }
bool IsSports { get; set; }
}
}

View File

@ -0,0 +1,9 @@
using System;
namespace MediaBrowser.Controller.Entities
{
public interface IHasStartDate
{
DateTime StartDate { get; set; }
}
}

View File

@ -73,6 +73,17 @@ namespace MediaBrowser.Controller.Entities
public string[] Tags { get; set; }
public string[] OfficialRatings { get; set; }
public DateTime? MinStartDate { get; set; }
public DateTime? MaxStartDate { get; set; }
public DateTime? MinEndDate { get; set; }
public DateTime? MaxEndDate { get; set; }
public bool? IsAiring { get; set; }
public bool? IsMovie { get; set; }
public bool? IsSports { get; set; }
public string[] ChannelIds { get; set; }
public InternalItemsQuery()
{
Tags = new string[] { };
@ -89,6 +100,7 @@ namespace MediaBrowser.Controller.Entities
Years = new int[] { };
PersonTypes = new string[] { };
PersonIds = new string[] { };
ChannelIds = new string[] { };
}
}
}

View File

@ -10,6 +10,7 @@ using System.Collections.Generic;
using System.IO;
using System.Threading;
using System.Threading.Tasks;
using MediaBrowser.Model.Querying;
namespace MediaBrowser.Controller.Library
{
@ -132,6 +133,13 @@ namespace MediaBrowser.Controller.Library
/// <returns>BaseItem.</returns>
BaseItem GetItemById(Guid id);
/// <summary>
/// Gets the items.
/// </summary>
/// <param name="query">The query.</param>
/// <returns>QueryResult&lt;BaseItem&gt;.</returns>
QueryResult<BaseItem> GetItems(InternalItemsQuery query);
/// <summary>
/// Gets the memory item by identifier.
/// </summary>

View File

@ -1,5 +1,4 @@
using MediaBrowser.Controller.Entities;
using MediaBrowser.Controller.Library;
using MediaBrowser.Controller.Providers;
using MediaBrowser.Model.Configuration;
using MediaBrowser.Model.LiveTv;
@ -7,12 +6,10 @@ using MediaBrowser.Model.Users;
using System;
using System.Linq;
using System.Runtime.Serialization;
using System.Threading;
using System.Threading.Tasks;
namespace MediaBrowser.Controller.LiveTv
{
public class LiveTvProgram : BaseItem, ILiveTvItem, IHasLookupInfo<LiveTvProgramLookupInfo>
public class LiveTvProgram : BaseItem, ILiveTvItem, IHasLookupInfo<LiveTvProgramLookupInfo>, IHasStartDate, IHasProgramAttributes
{
/// <summary>
/// Gets the user data key.
@ -28,12 +25,6 @@ namespace MediaBrowser.Controller.LiveTv
/// </summary>
public string ExternalId { get; set; }
/// <summary>
/// Gets or sets the channel identifier.
/// </summary>
/// <value>The channel identifier.</value>
public string ExternalChannelId { get; set; }
/// <summary>
/// Gets or sets the original air date.
/// </summary>
@ -204,15 +195,6 @@ namespace MediaBrowser.Controller.LiveTv
return "Program";
}
public override Task UpdateToRepository(ItemUpdateType updateReason, CancellationToken cancellationToken)
{
DateLastSaved = DateTime.UtcNow;
// Avoid library manager and keep out of in-memory cache
// Not great that this class has to know about that, but we'll improve that later.
return ItemRepository.SaveItem(this, cancellationToken);
}
protected override bool GetBlockUnratedValue(UserPolicy config)
{
return config.BlockUnratedItems.Contains(UnratedItem.LiveTvProgram);

View File

@ -149,10 +149,12 @@
<Compile Include="Entities\IHasOriginalTitle.cs" />
<Compile Include="Entities\IHasPreferredMetadataLanguage.cs" />
<Compile Include="Entities\IHasProductionLocations.cs" />
<Compile Include="Entities\IHasProgramAttributes.cs" />
<Compile Include="Entities\IHasScreenshots.cs" />
<Compile Include="Entities\IHasSeries.cs" />
<Compile Include="Entities\IHasShortOverview.cs" />
<Compile Include="Entities\IHasSpecialFeatures.cs" />
<Compile Include="Entities\IHasStartDate.cs" />
<Compile Include="Entities\IHasTaglines.cs" />
<Compile Include="Entities\IHasTags.cs" />
<Compile Include="Entities\IHasThemeMedia.cs" />

View File

@ -4,6 +4,7 @@ using System;
using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks;
using MediaBrowser.Model.Querying;
namespace MediaBrowser.Controller.Persistence
{
@ -102,13 +103,6 @@ namespace MediaBrowser.Controller.Persistence
/// <returns>IEnumerable{ChildDefinition}.</returns>
IEnumerable<Guid> GetChildren(Guid parentId);
/// <summary>
/// Gets the type of the items of.
/// </summary>
/// <param name="type">The type.</param>
/// <returns>IEnumerable{Guid}.</returns>
IEnumerable<Guid> GetItemIdsOfType(Type type);
/// <summary>
/// Saves the children.
/// </summary>
@ -135,11 +129,24 @@ namespace MediaBrowser.Controller.Persistence
Task SaveMediaStreams(Guid id, IEnumerable<MediaStream> streams, CancellationToken cancellationToken);
/// <summary>
/// Gets the type of the items of.
/// Gets the item ids.
/// </summary>
/// <param name="type">The type.</param>
/// <returns>IEnumerable&lt;BaseItem&gt;.</returns>
IEnumerable<BaseItem> GetItemsOfType(Type type);
/// <param name="query">The query.</param>
/// <returns>IEnumerable&lt;Guid&gt;.</returns>
QueryResult<Guid> GetItemIds(InternalItemsQuery query);
/// <summary>
/// Gets the items.
/// </summary>
/// <param name="query">The query.</param>
/// <returns>QueryResult&lt;BaseItem&gt;.</returns>
QueryResult<BaseItem> GetItems(InternalItemsQuery query);
/// <summary>
/// Gets the item ids list.
/// </summary>
/// <param name="query">The query.</param>
/// <returns>List&lt;Guid&gt;.</returns>
List<Guid> GetItemIdsList(InternalItemsQuery query);
}
}

View File

@ -1,21 +1,20 @@
using System.Linq;
using MediaBrowser.Common.Net;
using MediaBrowser.Common.Net;
using MediaBrowser.Controller.Channels;
using MediaBrowser.Controller.Entities;
using MediaBrowser.Controller.Entities.Movies;
using MediaBrowser.Controller.Entities.TV;
using MediaBrowser.Controller.Library;
using MediaBrowser.Controller.LiveTv;
using MediaBrowser.Controller.Providers;
using MediaBrowser.Model.Channels;
using MediaBrowser.Model.Entities;
using MediaBrowser.Model.Logging;
using MediaBrowser.Model.Providers;
using MediaBrowser.Model.Serialization;
using MediaBrowser.Providers.Movies;
using MediaBrowser.Providers.TV;
using System;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.Net;
using System.Threading;
using System.Threading.Tasks;
@ -23,7 +22,7 @@ using System.Threading.Tasks;
namespace MediaBrowser.Providers.Omdb
{
public class OmdbItemProvider : IRemoteMetadataProvider<Series, SeriesInfo>,
IRemoteMetadataProvider<Movie, MovieInfo>, IRemoteMetadataProvider<ChannelVideoItem, ChannelItemLookupInfo>
IRemoteMetadataProvider<Movie, MovieInfo>, IRemoteMetadataProvider<ChannelVideoItem, ChannelItemLookupInfo>, IRemoteMetadataProvider<LiveTvProgram, LiveTvProgramLookupInfo>
{
private readonly IJsonSerializer _jsonSerializer;
private readonly IHttpClient _httpClient;
@ -48,6 +47,16 @@ namespace MediaBrowser.Providers.Omdb
return GetSearchResults(searchInfo, "movie", cancellationToken);
}
public Task<IEnumerable<RemoteSearchResult>> GetSearchResults(LiveTvProgramLookupInfo searchInfo, CancellationToken cancellationToken)
{
if (!searchInfo.IsMovie)
{
return Task.FromResult<IEnumerable<RemoteSearchResult>>(new List<RemoteSearchResult>());
}
return GetSearchResults(searchInfo, "movie", cancellationToken);
}
public async Task<IEnumerable<RemoteSearchResult>> GetSearchResults(ItemLookupInfo searchInfo, string type, CancellationToken cancellationToken)
{
var list = new List<RemoteSearchResult>();
@ -169,13 +178,22 @@ namespace MediaBrowser.Providers.Omdb
return result;
}
public Task<MetadataResult<LiveTvProgram>> GetMetadata(LiveTvProgramLookupInfo info, CancellationToken cancellationToken)
{
if (!info.IsMovie)
{
return Task.FromResult(new MetadataResult<LiveTvProgram>());
}
return GetMovieResult<LiveTvProgram>(info, cancellationToken);
}
public Task<MetadataResult<Movie>> GetMetadata(MovieInfo info, CancellationToken cancellationToken)
{
return GetMovieResult<Movie>(info, cancellationToken);
}
private async Task<MetadataResult<T>> GetMovieResult<T>(ItemLookupInfo info, CancellationToken cancellationToken)
where T : Video, new()
where T : BaseItem, new()
{
var result = new MetadataResult<T>
{

View File

@ -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);

View File

@ -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>

View File

@ -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;
return _libraryManager.GetItemById(id) as LiveTvProgram;
}
private void RefreshIfNeeded(LiveTvProgram program)
internal LiveTvProgram GetInternalProgram(Guid id)
{
if (!_refreshedPrograms.ContainsKey(program.Id))
{
_refreshedPrograms.TryAdd(program.Id, true);
_providerManager.QueueRefresh(program.Id, new MetadataRefreshOptions());
}
}
private void RefreshIfNeeded(IEnumerable<LiveTvProgram> programs)
{
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,55 +700,36 @@ 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.HasAired.Value)
{
internalQuery.MaxEndDate = DateTime.UtcNow;
}
else
{
internalQuery.MinEndDate = DateTime.UtcNow;
}
}
if (query.ChannelIds.Length > 0)
IEnumerable<LiveTvProgram> programs = _libraryManager.GetItems(internalQuery).Items.Cast<LiveTvProgram>();
// Apply genre filter
if (query.Genres.Length > 0)
{
var guids = query.ChannelIds.Select(i => new Guid(i)).ToList();
programs = programs.Where(i =>
{
var programChannelId = i.ExternalChannelId;
var service = GetService(i);
var internalProgramChannelId = _tvDtoService.GetInternalChannelId(service.Name, programChannelId);
return guids.Contains(internalProgramChannelId);
});
programs = programs.Where(p => p.Genres.Any(g => query.Genres.Contains(g, StringComparer.OrdinalIgnoreCase)));
}
var user = string.IsNullOrEmpty(query.UserId) ? null : _userManager.GetUserById(query.UserId);
@ -804,22 +740,6 @@ namespace MediaBrowser.Server.Implementations.LiveTv
programs = programs.Where(i => i.IsVisible(currentUser));
}
// Apply genre filter
if (query.Genres.Length > 0)
{
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)
{
programs = programs.Where(p => p.IsSports == query.IsSports);
}
programs = _libraryManager.Sort(programs, user, query.SortBy, query.SortOrder ?? SortOrder.Ascending)
.Cast<LiveTvProgram>();
@ -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,7 +773,27 @@ namespace MediaBrowser.Server.Implementations.LiveTv
public async Task<QueryResult<LiveTvProgram>> GetRecommendedProgramsInternal(RecommendedProgramQuery query, CancellationToken cancellationToken)
{
IEnumerable<LiveTvProgram> programs = GetPrograms();
var internalQuery = new InternalItemsQuery
{
IncludeItemTypes = new[] { typeof(LiveTvProgram).Name },
IsAiring = query.IsAiring,
IsMovie = query.IsMovie,
IsSports = query.IsSports
};
if (query.HasAired.HasValue)
{
if (query.HasAired.Value)
{
internalQuery.MaxEndDate = DateTime.UtcNow;
}
else
{
internalQuery.MinEndDate = DateTime.UtcNow;
}
}
IEnumerable<LiveTvProgram> programs = _libraryManager.GetItems(internalQuery).Items.Cast<LiveTvProgram>();
var user = _userManager.GetUserById(query.UserId);
@ -863,28 +801,6 @@ namespace MediaBrowser.Server.Implementations.LiveTv
var currentUser = user;
programs = programs.Where(i => i.IsVisible(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);
}
if (query.IsMovie.HasValue)
{
programs = programs.Where(p => p.IsMovie == query.IsMovie.Value);
}
if (query.IsSports.HasValue)
{
programs = programs.Where(p => p.IsSports == query.IsSports.Value);
}
var programList = programs.ToList();
var genres = programList.SelectMany(i => i.Genres)
@ -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);
return new Tuple<List<Guid>,List<Guid>>(channels, programs);
}
private Task CleanDatabaseInternal(IProgress<double> progress, CancellationToken cancellationToken)
private async Task CleanDatabaseInternal(List<Guid> currentIdList, string typeName, IProgress<double> progress, CancellationToken cancellationToken)
{
return DeleteOldPrograms(GetProgramsDictionary().Keys.ToList(), progress, cancellationToken);
}
var list = _itemRepo.GetItemIds(new InternalItemsQuery
{
IncludeItemTypes = new[] { typeName }
private async Task DeleteOldPrograms(List<Guid> currentIdList, IProgress<double> progress, CancellationToken cancellationToken)
{
var list = _itemRepo.GetItemIdsOfType(typeof(LiveTvProgram)).ToList();
}).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,31 +1584,27 @@ namespace MediaBrowser.Server.Implementations.LiveTv
{
var channel = GetInternalChannel(id);
var currentProgram = GetCurrentProgram(channel.ExternalId);
var now = DateTime.UtcNow;
var programs = _libraryManager.GetItems(new InternalItemsQuery
{
IncludeItemTypes = new[] { typeof(LiveTvProgram).Name },
ChannelIds = new[] { id },
MaxStartDate = now,
MinEndDate = now,
Limit = 1
}).Items.Cast<LiveTvProgram>();
var currentProgram = programs
.OrderBy(i => i.StartDate)
.FirstOrDefault();
var dto = _tvDtoService.GetChannelInfoDto(channel, currentProgram, user);
return dto;
}
private LiveTvProgram GetCurrentProgram(string externalChannelId)
{
var now = DateTime.UtcNow;
var program = GetPrograms()
.Where(i => string.Equals(externalChannelId, i.ExternalChannelId, StringComparison.OrdinalIgnoreCase))
.OrderBy(i => i.StartDate)
.SkipWhile(i => now >= (i.EndDate ?? DateTime.MinValue))
.FirstOrDefault();
if (program != null)
{
RefreshIfNeeded(program);
}
return program;
}
private async Task<Tuple<SeriesTimerInfo, ILiveTvService>> GetNewTimerDefaultsInternal(CancellationToken cancellationToken, LiveTvProgram program = null)
{
var service = program != null && !string.IsNullOrWhiteSpace(program.ServiceName) ?
@ -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
{

View File

@ -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)
{

View File

@ -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";
@ -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();
@ -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)