update recording database

pull/702/head
Luke Pulverenti 9 years ago
parent 17fe8caee4
commit 418bb87878

@ -0,0 +1,9 @@
using System;
namespace MediaBrowser.Controller.Entities
{
public interface IHasId
{
Guid Id { get; }
}
}

@ -1,13 +1,12 @@
using MediaBrowser.Controller.Providers; using MediaBrowser.Controller.Providers;
using MediaBrowser.Model.Entities; using MediaBrowser.Model.Entities;
using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.IO; using System.IO;
using System.Threading.Tasks; using System.Threading.Tasks;
namespace MediaBrowser.Controller.Entities namespace MediaBrowser.Controller.Entities
{ {
public interface IHasImages : IHasProviderIds public interface IHasImages : IHasProviderIds, IHasId
{ {
/// <summary> /// <summary>
/// Gets the name. /// Gets the name.
@ -27,12 +26,6 @@ namespace MediaBrowser.Controller.Entities
/// <value>The file name without extension.</value> /// <value>The file name without extension.</value>
string FileNameWithoutExtension { get; } string FileNameWithoutExtension { get; }
/// <summary>
/// Gets the identifier.
/// </summary>
/// <value>The identifier.</value>
Guid Id { get; }
/// <summary> /// <summary>
/// Gets the type of the location. /// Gets the type of the location.
/// </summary> /// </summary>

@ -1,17 +1,10 @@
using MediaBrowser.Model.Dto; using MediaBrowser.Model.Dto;
using System;
using System.Collections.Generic; using System.Collections.Generic;
namespace MediaBrowser.Controller.Entities namespace MediaBrowser.Controller.Entities
{ {
public interface IHasMediaSources public interface IHasMediaSources : IHasId
{ {
/// <summary>
/// Gets the identifier.
/// </summary>
/// <value>The identifier.</value>
Guid Id { get; }
/// <summary> /// <summary>
/// Gets the media sources. /// Gets the media sources.
/// </summary> /// </summary>

@ -1,9 +1,19 @@
 using MediaBrowser.Model.LiveTv;
using System;
namespace MediaBrowser.Controller.Entities namespace MediaBrowser.Controller.Entities
{ {
public interface IHasProgramAttributes public interface IHasProgramAttributes
{ {
bool IsMovie { get; set; } bool IsMovie { get; set; }
bool IsSports { get; set; } bool IsSports { get; set; }
bool IsNews { get; set; }
bool IsKids { get; set; }
bool IsRepeat { get; set; }
bool? IsHD { get; set; }
bool IsLive { get; set; }
bool IsPremiere { get; set; }
ProgramAudio? Audio { get; set; }
DateTime? OriginalAirDate { get; set; }
} }
} }

@ -1,19 +1,12 @@
using MediaBrowser.Model.Dto; using MediaBrowser.Model.Dto;
using System;
namespace MediaBrowser.Controller.Entities namespace MediaBrowser.Controller.Entities
{ {
/// <summary> /// <summary>
/// Interface IHasUserData /// Interface IHasUserData
/// </summary> /// </summary>
public interface IHasUserData public interface IHasUserData : IHasId
{ {
/// <summary>
/// Gets or sets the identifier.
/// </summary>
/// <value>The identifier.</value>
Guid Id { get; set; }
/// <summary> /// <summary>
/// Gets the user data key. /// Gets the user data key.
/// </summary> /// </summary>

@ -1,10 +1,9 @@
using System; using MediaBrowser.Controller.Entities;
namespace MediaBrowser.Controller.LiveTv namespace MediaBrowser.Controller.LiveTv
{ {
public interface ILiveTvItem public interface ILiveTvItem : IHasId
{ {
Guid Id { get; }
string ServiceName { get; set; } string ServiceName { get; set; }
} }
} }

@ -2,19 +2,21 @@
using MediaBrowser.Controller.Library; using MediaBrowser.Controller.Library;
using MediaBrowser.Controller.Providers; using MediaBrowser.Controller.Providers;
using MediaBrowser.Model.Library; using MediaBrowser.Model.Library;
using MediaBrowser.Model.LiveTv;
using System;
using System.Threading; using System.Threading;
using System.Threading.Tasks; using System.Threading.Tasks;
namespace MediaBrowser.Controller.LiveTv namespace MediaBrowser.Controller.LiveTv
{ {
public interface ILiveTvRecording : IHasImages, IHasMediaSources, IHasUserData, ILiveTvItem public interface ILiveTvRecording : IHasImages, IHasMediaSources, IHasUserData, ILiveTvItem, IHasStartDate, IHasProgramAttributes
{ {
string ChannelId { get; }
string ProgramId { get; set; }
string MediaType { get; } string MediaType { get; }
string Container { get; } string Container { get; }
RecordingInfo RecordingInfo { get; set; }
long? RunTimeTicks { get; set; } long? RunTimeTicks { get; set; }
string GetClientTypeName(); string GetClientTypeName();
@ -28,5 +30,17 @@ namespace MediaBrowser.Controller.LiveTv
bool CanDelete(); bool CanDelete();
bool CanDelete(User user); bool CanDelete(User user);
string ProviderImagePath { get; set; }
string ProviderImageUrl { get; set; }
string ExternalId { get; set; }
string EpisodeTitle { get; set; }
bool IsSeries { get; set; }
string SeriesTimerId { get; set; }
RecordingStatus Status { get; set; }
DateTime? EndDate { get; set; }
ChannelType ChannelType { get; set; }
} }
} }

@ -3,7 +3,9 @@ using MediaBrowser.Controller.Entities.Audio;
using MediaBrowser.Model.Configuration; using MediaBrowser.Model.Configuration;
using MediaBrowser.Model.Dto; using MediaBrowser.Model.Dto;
using MediaBrowser.Model.Entities; using MediaBrowser.Model.Entities;
using MediaBrowser.Model.LiveTv;
using MediaBrowser.Model.Users; using MediaBrowser.Model.Users;
using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Runtime.Serialization; using System.Runtime.Serialization;
@ -12,6 +14,27 @@ namespace MediaBrowser.Controller.LiveTv
{ {
public class LiveTvAudioRecording : Audio, ILiveTvRecording public class LiveTvAudioRecording : Audio, ILiveTvRecording
{ {
public string ExternalId { get; set; }
public string ProviderImagePath { get; set; }
public string ProviderImageUrl { get; set; }
public string EpisodeTitle { get; set; }
public bool IsSeries { get; set; }
public string SeriesTimerId { get; set; }
public DateTime StartDate { get; set; }
public RecordingStatus Status { get; set; }
public bool IsSports { get; set; }
public bool IsNews { get; set; }
public bool IsKids { get; set; }
public bool IsRepeat { get; set; }
public bool IsMovie { get; set; }
public bool? IsHD { get; set; }
public bool IsLive { get; set; }
public bool IsPremiere { get; set; }
public ChannelType ChannelType { get; set; }
public string ProgramId { get; set; }
public ProgramAudio? Audio { get; set; }
public DateTime? OriginalAirDate { get; set; }
/// <summary> /// <summary>
/// Gets the user data key. /// Gets the user data key.
/// </summary> /// </summary>

@ -2,7 +2,9 @@
using MediaBrowser.Model.Configuration; using MediaBrowser.Model.Configuration;
using MediaBrowser.Model.Dto; using MediaBrowser.Model.Dto;
using MediaBrowser.Model.Entities; using MediaBrowser.Model.Entities;
using MediaBrowser.Model.LiveTv;
using MediaBrowser.Model.Users; using MediaBrowser.Model.Users;
using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Runtime.Serialization; using System.Runtime.Serialization;
@ -11,6 +13,27 @@ namespace MediaBrowser.Controller.LiveTv
{ {
public class LiveTvVideoRecording : Video, ILiveTvRecording public class LiveTvVideoRecording : Video, ILiveTvRecording
{ {
public string ExternalId { get; set; }
public string ProviderImagePath { get; set; }
public string ProviderImageUrl { get; set; }
public string EpisodeTitle { get; set; }
public bool IsSeries { get; set; }
public string SeriesTimerId { get; set; }
public DateTime StartDate { get; set; }
public RecordingStatus Status { get; set; }
public bool IsSports { get; set; }
public bool IsNews { get; set; }
public bool IsKids { get; set; }
public bool IsRepeat { get; set; }
public bool IsMovie { get; set; }
public bool? IsHD { get; set; }
public bool IsLive { get; set; }
public bool IsPremiere { get; set; }
public ChannelType ChannelType { get; set; }
public string ProgramId { get; set; }
public ProgramAudio? Audio { get; set; }
public DateTime? OriginalAirDate { get; set; }
/// <summary> /// <summary>
/// Gets the user data key. /// Gets the user data key.
/// </summary> /// </summary>

@ -142,6 +142,7 @@
<Compile Include="Entities\IHasBudget.cs" /> <Compile Include="Entities\IHasBudget.cs" />
<Compile Include="Entities\IHasCriticRating.cs" /> <Compile Include="Entities\IHasCriticRating.cs" />
<Compile Include="Entities\IHasDisplayOrder.cs" /> <Compile Include="Entities\IHasDisplayOrder.cs" />
<Compile Include="Entities\IHasId.cs" />
<Compile Include="Entities\IHasImages.cs" /> <Compile Include="Entities\IHasImages.cs" />
<Compile Include="Entities\IHasKeywords.cs" /> <Compile Include="Entities\IHasKeywords.cs" />
<Compile Include="Entities\IHasMediaSources.cs" /> <Compile Include="Entities\IHasMediaSources.cs" />

@ -290,7 +290,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv
public Guid GetInternalRecordingId(string serviceName, string externalId) public Guid GetInternalRecordingId(string serviceName, string externalId)
{ {
var name = serviceName + externalId + InternalVersionNumber; var name = serviceName + externalId + InternalVersionNumber + "0";
return name.ToLower().GetMBId(typeof(ILiveTvRecording)); return name.ToLower().GetMBId(typeof(ILiveTvRecording));
} }

@ -53,6 +53,8 @@ namespace MediaBrowser.Server.Implementations.LiveTv
private readonly ConcurrentDictionary<string, LiveStreamData> _openStreams = private readonly ConcurrentDictionary<string, LiveStreamData> _openStreams =
new ConcurrentDictionary<string, LiveStreamData>(); new ConcurrentDictionary<string, LiveStreamData>();
private readonly SemaphoreSlim _refreshRecordingsLock = new SemaphoreSlim(1, 1);
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) 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; _config = config;
@ -359,8 +361,8 @@ namespace MediaBrowser.Server.Implementations.LiveTv
isVideo = !string.Equals(recording.MediaType, MediaType.Audio, StringComparison.OrdinalIgnoreCase); isVideo = !string.Equals(recording.MediaType, MediaType.Audio, StringComparison.OrdinalIgnoreCase);
var service = GetService(recording); var service = GetService(recording);
_logger.Info("Opening recording stream from {0}, external recording Id: {1}", service.Name, recording.RecordingInfo.Id); _logger.Info("Opening recording stream from {0}, external recording Id: {1}", service.Name, recording.ExternalId);
info = await service.GetRecordingStream(recording.RecordingInfo.Id, null, cancellationToken).ConfigureAwait(false); info = await service.GetRecordingStream(recording.ExternalId, null, cancellationToken).ConfigureAwait(false);
info.RequiresClosing = true; info.RequiresClosing = true;
if (info.RequiresClosing) if (info.RequiresClosing)
@ -618,7 +620,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv
return item; return item;
} }
private async Task<ILiveTvRecording> GetRecording(RecordingInfo info, string serviceName, CancellationToken cancellationToken) private async Task<Guid> CreateRecordingRecord(RecordingInfo info, string serviceName, CancellationToken cancellationToken)
{ {
var isNew = false; var isNew = false;
@ -653,14 +655,36 @@ namespace MediaBrowser.Server.Implementations.LiveTv
isNew = true; isNew = true;
} }
item.ChannelId = _tvDtoService.GetInternalChannelId(serviceName, info.ChannelId).ToString("N");
item.CommunityRating = info.CommunityRating; item.CommunityRating = info.CommunityRating;
item.OfficialRating = info.OfficialRating; item.OfficialRating = info.OfficialRating;
item.Overview = info.Overview; item.Overview = info.Overview;
item.EndDate = info.EndDate; item.EndDate = info.EndDate;
item.Genres = info.Genres;
var recording = (ILiveTvRecording)item; var recording = (ILiveTvRecording)item;
recording.RecordingInfo = info; recording.ProgramId = _tvDtoService.GetInternalProgramId(serviceName, info.ProgramId).ToString("N");
recording.Audio = info.Audio;
recording.ChannelType = info.ChannelType;
recording.EndDate = info.EndDate;
recording.EpisodeTitle = info.EpisodeTitle;
recording.ProviderImagePath = info.ImagePath;
recording.ProviderImageUrl = info.ImageUrl;
recording.IsHD = info.IsHD;
recording.IsKids = info.IsKids;
recording.IsLive = info.IsLive;
recording.IsMovie = info.IsMovie;
recording.IsNews = info.IsNews;
recording.IsPremiere = info.IsPremiere;
recording.IsRepeat = info.IsRepeat;
recording.IsSeries = info.IsSeries;
recording.IsSports = info.IsSports;
recording.OriginalAirDate = info.OriginalAirDate;
recording.SeriesTimerId = info.SeriesTimerId;
recording.StartDate = info.StartDate;
recording.Status = info.Status;
recording.ServiceName = serviceName; recording.ServiceName = serviceName;
var originalPath = item.Path; var originalPath = item.Path;
@ -676,15 +700,18 @@ namespace MediaBrowser.Server.Implementations.LiveTv
var pathChanged = !string.Equals(originalPath, item.Path); var pathChanged = !string.Equals(originalPath, item.Path);
await item.RefreshMetadata(new MetadataRefreshOptions if (isNew)
{ {
ForceSave = isNew || pathChanged await _libraryManager.CreateItem(item, cancellationToken).ConfigureAwait(false);
}
}, cancellationToken); else if (pathChanged)
{
await _libraryManager.UpdateItem(item, ItemUpdateType.MetadataImport, cancellationToken).ConfigureAwait(false);
}
_libraryManager.RegisterItem(item); _providerManager.QueueRefresh(item.Id, new MetadataRefreshOptions());
return recording; return item.Id;
} }
public async Task<BaseItemDto> GetProgram(string id, CancellationToken cancellationToken, User user = null) public async Task<BaseItemDto> GetProgram(string id, CancellationToken cancellationToken, User user = null)
@ -1006,8 +1033,8 @@ namespace MediaBrowser.Server.Implementations.LiveTv
progress.Report(100 * percent); progress.Report(100 * percent);
} }
await CleanDatabaseInternal(newChannelIdList, typeof(LiveTvChannel).Name, progress, cancellationToken).ConfigureAwait(false); await CleanDatabaseInternal(newChannelIdList, new[] { typeof(LiveTvChannel).Name }, progress, cancellationToken).ConfigureAwait(false);
await CleanDatabaseInternal(newProgramIdList, typeof(LiveTvProgram).Name, progress, cancellationToken).ConfigureAwait(false); await CleanDatabaseInternal(newProgramIdList, new[] { typeof(LiveTvProgram).Name }, progress, cancellationToken).ConfigureAwait(false);
// Load these now which will prefetch metadata // Load these now which will prefetch metadata
var dtoOptions = new DtoOptions(); var dtoOptions = new DtoOptions();
@ -1017,7 +1044,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv
progress.Report(100); progress.Report(100);
} }
private async Task<Tuple<List<Guid>,List<Guid>>> 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); progress.Report(10);
@ -1103,14 +1130,14 @@ namespace MediaBrowser.Server.Implementations.LiveTv
} }
progress.Report(100); progress.Report(100);
return new Tuple<List<Guid>,List<Guid>>(channels, programs); return new Tuple<List<Guid>, List<Guid>>(channels, programs);
} }
private async Task CleanDatabaseInternal(List<Guid> currentIdList, string typeName, IProgress<double> progress, CancellationToken cancellationToken) private async Task CleanDatabaseInternal(List<Guid> currentIdList, string[] validTypes, IProgress<double> progress, CancellationToken cancellationToken)
{ {
var list = _itemRepo.GetItemIds(new InternalItemsQuery var list = _itemRepo.GetItemIds(new InternalItemsQuery
{ {
IncludeItemTypes = new[] { typeName } IncludeItemTypes = validTypes
}).Items.ToList(); }).Items.ToList();
@ -1163,64 +1190,103 @@ namespace MediaBrowser.Server.Implementations.LiveTv
return channels.Select(i => new Tuple<string, ChannelInfo>(service.Name, i)); return channels.Select(i => new Tuple<string, ChannelInfo>(service.Name, i));
} }
public async Task<QueryResult<BaseItem>> GetInternalRecordings(RecordingQuery query, CancellationToken cancellationToken) private DateTime _lastRecordingRefreshTime;
private async Task RefreshRecordings(CancellationToken cancellationToken)
{ {
var tasks = _services.Select(async i => const int cacheMinutes = 5;
if ((DateTime.UtcNow - _lastRecordingRefreshTime).TotalMinutes < cacheMinutes)
{ {
try return;
}
await _refreshRecordingsLock.WaitAsync(cancellationToken).ConfigureAwait(false);
try
{
if ((DateTime.UtcNow - _lastRecordingRefreshTime).TotalMinutes < cacheMinutes)
{ {
var recs = await i.GetRecordingsAsync(cancellationToken).ConfigureAwait(false); return;
return recs.Select(r => new Tuple<RecordingInfo, ILiveTvService>(r, i));
} }
catch (Exception ex)
var tasks = _services.Select(async i =>
{ {
_logger.ErrorException("Error getting recordings", ex); try
return new List<Tuple<RecordingInfo, ILiveTvService>>(); {
} var recs = await i.GetRecordingsAsync(cancellationToken).ConfigureAwait(false);
}); return recs.Select(r => new Tuple<RecordingInfo, ILiveTvService>(r, i));
var results = await Task.WhenAll(tasks).ConfigureAwait(false); }
var recordings = results.SelectMany(i => i.ToList()); catch (Exception ex)
{
_logger.ErrorException("Error getting recordings", ex);
return new List<Tuple<RecordingInfo, ILiveTvService>>();
}
});
var user = string.IsNullOrEmpty(query.UserId) ? null : _userManager.GetUserById(query.UserId); var results = await Task.WhenAll(tasks).ConfigureAwait(false);
var recordingTasks = results.SelectMany(i => i.ToList()).Select(i => CreateRecordingRecord(i.Item1, i.Item2.Name, cancellationToken));
var idList = await Task.WhenAll(recordingTasks).ConfigureAwait(false);
CleanDatabaseInternal(idList.ToList(), new[] { typeof(LiveTvVideoRecording).Name, typeof(LiveTvAudioRecording).Name }, new Progress<double>(), cancellationToken).ConfigureAwait(false);
_lastRecordingRefreshTime = DateTime.UtcNow;
}
finally
{
_refreshRecordingsLock.Release();
}
}
public async Task<QueryResult<BaseItem>> GetInternalRecordings(RecordingQuery query, CancellationToken cancellationToken)
{
var user = string.IsNullOrEmpty(query.UserId) ? null : _userManager.GetUserById(query.UserId);
if (user != null && !IsLiveTvEnabled(user)) if (user != null && !IsLiveTvEnabled(user))
{ {
recordings = new List<Tuple<RecordingInfo, ILiveTvService>>(); return new QueryResult<BaseItem>();
} }
if (!string.IsNullOrEmpty(query.ChannelId)) await RefreshRecordings(cancellationToken).ConfigureAwait(false);
var internalQuery = new InternalItemsQuery
{ {
var guid = new Guid(query.ChannelId); IncludeItemTypes = new[] { typeof(LiveTvVideoRecording).Name, typeof(LiveTvAudioRecording).Name }
};
recordings = recordings if (!string.IsNullOrEmpty(query.ChannelId))
.Where(i => _tvDtoService.GetInternalChannelId(i.Item2.Name, i.Item1.ChannelId) == guid); {
internalQuery.ChannelIds = new[] { query.ChannelId };
} }
var queryResult = _libraryManager.GetItems(internalQuery);
IEnumerable<ILiveTvRecording> recordings = queryResult.Items.Cast<ILiveTvRecording>();
if (!string.IsNullOrEmpty(query.Id)) if (!string.IsNullOrEmpty(query.Id))
{ {
var guid = new Guid(query.Id); var guid = new Guid(query.Id);
recordings = recordings recordings = recordings
.Where(i => _tvDtoService.GetInternalRecordingId(i.Item2.Name, i.Item1.Id) == guid); .Where(i => i.Id == guid);
} }
if (!string.IsNullOrEmpty(query.GroupId)) if (!string.IsNullOrEmpty(query.GroupId))
{ {
var guid = new Guid(query.GroupId); var guid = new Guid(query.GroupId);
recordings = recordings.Where(i => GetRecordingGroupIds(i.Item1).Contains(guid)); recordings = recordings.Where(i => GetRecordingGroupIds(i).Contains(guid));
} }
if (query.IsInProgress.HasValue) if (query.IsInProgress.HasValue)
{ {
var val = query.IsInProgress.Value; var val = query.IsInProgress.Value;
recordings = recordings.Where(i => (i.Item1.Status == RecordingStatus.InProgress) == val); recordings = recordings.Where(i => (i.Status == RecordingStatus.InProgress) == val);
} }
if (query.Status.HasValue) if (query.Status.HasValue)
{ {
var val = query.Status.Value; var val = query.Status.Value;
recordings = recordings.Where(i => (i.Item1.Status == val)); recordings = recordings.Where(i => (i.Status == val));
} }
if (!string.IsNullOrEmpty(query.SeriesTimerId)) if (!string.IsNullOrEmpty(query.SeriesTimerId))
@ -1228,21 +1294,19 @@ namespace MediaBrowser.Server.Implementations.LiveTv
var guid = new Guid(query.SeriesTimerId); var guid = new Guid(query.SeriesTimerId);
recordings = recordings recordings = recordings
.Where(i => _tvDtoService.GetInternalSeriesTimerId(i.Item2.Name, i.Item1.SeriesTimerId) == guid); .Where(i => _tvDtoService.GetInternalSeriesTimerId(i.ServiceName, i.SeriesTimerId) == guid);
} }
recordings = recordings.OrderByDescending(i => i.Item1.StartDate);
IEnumerable<ILiveTvRecording> entities = await GetEntities(recordings, cancellationToken).ConfigureAwait(false);
if (user != null) if (user != null)
{ {
var currentUser = user; var currentUser = user;
entities = entities.Where(i => i.IsParentalAllowed(currentUser)); recordings = recordings.Where(i => i.IsParentalAllowed(currentUser));
} }
var entityList = entities.ToList(); recordings = recordings.OrderByDescending(i => i.StartDate);
entities = entityList;
var entityList = recordings.ToList();
IEnumerable<ILiveTvRecording> entities = entityList;
if (query.StartIndex.HasValue) if (query.StartIndex.HasValue)
{ {
@ -1270,7 +1334,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv
dto.Id = _tvDtoService.GetInternalProgramId(service.Name, program.ExternalId).ToString("N"); dto.Id = _tvDtoService.GetInternalProgramId(service.Name, program.ExternalId).ToString("N");
dto.ChannelId = channel.Id.ToString("N"); dto.ChannelId = item.ChannelId;
dto.StartDate = program.StartDate; dto.StartDate = program.StartDate;
dto.IsRepeat = program.IsRepeat; dto.IsRepeat = program.IsRepeat;
@ -1303,16 +1367,16 @@ namespace MediaBrowser.Server.Implementations.LiveTv
var recording = (ILiveTvRecording)item; var recording = (ILiveTvRecording)item;
var service = GetService(recording); var service = GetService(recording);
var channel = string.IsNullOrEmpty(recording.RecordingInfo.ChannelId) ? null : GetInternalChannel(_tvDtoService.GetInternalChannelId(service.Name, recording.RecordingInfo.ChannelId)); var channel = string.IsNullOrWhiteSpace(recording.ChannelId) ? null : GetInternalChannel(recording.ChannelId);
var info = recording.RecordingInfo; var info = recording;
dto.Id = _tvDtoService.GetInternalRecordingId(service.Name, info.Id).ToString("N"); dto.Id = item.Id.ToString("N");
dto.SeriesTimerId = string.IsNullOrEmpty(info.SeriesTimerId) dto.SeriesTimerId = string.IsNullOrEmpty(info.SeriesTimerId)
? null ? null
: _tvDtoService.GetInternalSeriesTimerId(service.Name, info.SeriesTimerId).ToString("N"); : _tvDtoService.GetInternalSeriesTimerId(service.Name, info.SeriesTimerId).ToString("N");
dto.ChannelId = _tvDtoService.GetInternalChannelId(service.Name, info.ChannelId).ToString("N"); dto.ChannelId = item.ChannelId;
dto.StartDate = info.StartDate; dto.StartDate = info.StartDate;
dto.RecordingStatus = info.Status; dto.RecordingStatus = info.Status;
@ -1344,11 +1408,11 @@ namespace MediaBrowser.Server.Implementations.LiveTv
dto.MediaStreams = dto.MediaSources.SelectMany(i => i.MediaStreams).ToList(); dto.MediaStreams = dto.MediaSources.SelectMany(i => i.MediaStreams).ToList();
} }
if (info.Status == RecordingStatus.InProgress) if (info.Status == RecordingStatus.InProgress && info.EndDate.HasValue)
{ {
var now = DateTime.UtcNow.Ticks; var now = DateTime.UtcNow.Ticks;
var start = info.StartDate.Ticks; var start = info.StartDate.Ticks;
var end = info.EndDate.Ticks; var end = info.EndDate.Value.Ticks;
var pct = now - start; var pct = now - start;
pct /= end; pct /= end;
@ -1356,10 +1420,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv
dto.CompletionPercentage = pct; dto.CompletionPercentage = pct;
} }
if (!string.IsNullOrEmpty(info.ProgramId)) dto.ProgramId = info.ProgramId;
{
dto.ProgramId = _tvDtoService.GetInternalProgramId(service.Name, info.ProgramId).ToString("N");
}
if (channel != null) if (channel != null)
{ {
@ -1394,13 +1455,6 @@ namespace MediaBrowser.Server.Implementations.LiveTv
}; };
} }
private Task<ILiveTvRecording[]> GetEntities(IEnumerable<Tuple<RecordingInfo, ILiveTvService>> recordings, CancellationToken cancellationToken)
{
var tasks = recordings.Select(i => GetRecording(i.Item1, i.Item2.Name, cancellationToken));
return Task.WhenAll(tasks);
}
public async Task<QueryResult<TimerInfoDto>> GetTimers(TimerQuery query, CancellationToken cancellationToken) public async Task<QueryResult<TimerInfoDto>> GetTimers(TimerQuery query, CancellationToken cancellationToken)
{ {
var tasks = _services.Select(async i => var tasks = _services.Select(async i =>
@ -1468,7 +1522,8 @@ namespace MediaBrowser.Server.Implementations.LiveTv
var service = GetService(recording.ServiceName); var service = GetService(recording.ServiceName);
await service.DeleteRecordingAsync(recording.RecordingInfo.Id, CancellationToken.None).ConfigureAwait(false); await service.DeleteRecordingAsync(recording.ExternalId, CancellationToken.None).ConfigureAwait(false);
_lastRecordingRefreshTime = DateTime.MinValue;
} }
public async Task CancelTimer(string id) public async Task CancelTimer(string id)
@ -1483,6 +1538,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv
var service = GetService(timer.ServiceName); var service = GetService(timer.ServiceName);
await service.CancelTimerAsync(timer.ExternalId, CancellationToken.None).ConfigureAwait(false); await service.CancelTimerAsync(timer.ExternalId, CancellationToken.None).ConfigureAwait(false);
_lastRecordingRefreshTime = DateTime.MinValue;
} }
public async Task CancelSeriesTimer(string id) public async Task CancelSeriesTimer(string id)
@ -1497,6 +1553,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv
var service = GetService(timer.ServiceName); var service = GetService(timer.ServiceName);
await service.CancelSeriesTimerAsync(timer.ExternalId, CancellationToken.None).ConfigureAwait(false); await service.CancelSeriesTimerAsync(timer.ExternalId, CancellationToken.None).ConfigureAwait(false);
_lastRecordingRefreshTime = DateTime.MinValue;
} }
public async Task<BaseItemDto> GetRecording(string id, DtoOptions options, CancellationToken cancellationToken, User user = null) public async Task<BaseItemDto> GetRecording(string id, DtoOptions options, CancellationToken cancellationToken, User user = null)
@ -1705,6 +1762,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv
info.Priority = defaultValues.Priority; info.Priority = defaultValues.Priority;
await service.CreateTimerAsync(info, cancellationToken).ConfigureAwait(false); await service.CreateTimerAsync(info, cancellationToken).ConfigureAwait(false);
_lastRecordingRefreshTime = DateTime.MinValue;
} }
public async Task CreateSeriesTimer(SeriesTimerInfoDto timer, CancellationToken cancellationToken) public async Task CreateSeriesTimer(SeriesTimerInfoDto timer, CancellationToken cancellationToken)
@ -1718,6 +1776,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv
info.Priority = defaultValues.Priority; info.Priority = defaultValues.Priority;
await service.CreateSeriesTimerAsync(info, cancellationToken).ConfigureAwait(false); await service.CreateSeriesTimerAsync(info, cancellationToken).ConfigureAwait(false);
_lastRecordingRefreshTime = DateTime.MinValue;
} }
public async Task UpdateTimer(TimerInfoDto timer, CancellationToken cancellationToken) public async Task UpdateTimer(TimerInfoDto timer, CancellationToken cancellationToken)
@ -1727,6 +1786,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv
var service = GetService(timer.ServiceName); var service = GetService(timer.ServiceName);
await service.UpdateTimerAsync(info, cancellationToken).ConfigureAwait(false); await service.UpdateTimerAsync(info, cancellationToken).ConfigureAwait(false);
_lastRecordingRefreshTime = DateTime.MinValue;
} }
public async Task UpdateSeriesTimer(SeriesTimerInfoDto timer, CancellationToken cancellationToken) public async Task UpdateSeriesTimer(SeriesTimerInfoDto timer, CancellationToken cancellationToken)
@ -1736,9 +1796,10 @@ namespace MediaBrowser.Server.Implementations.LiveTv
var service = GetService(timer.ServiceName); var service = GetService(timer.ServiceName);
await service.UpdateSeriesTimerAsync(info, cancellationToken).ConfigureAwait(false); await service.UpdateSeriesTimerAsync(info, cancellationToken).ConfigureAwait(false);
_lastRecordingRefreshTime = DateTime.MinValue;
} }
private IEnumerable<string> GetRecordingGroupNames(RecordingInfo recording) private IEnumerable<string> GetRecordingGroupNames(ILiveTvRecording recording)
{ {
var list = new List<string>(); var list = new List<string>();
@ -1775,7 +1836,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv
return list; return list;
} }
private List<Guid> GetRecordingGroupIds(RecordingInfo recording) private List<Guid> GetRecordingGroupIds(ILiveTvRecording recording)
{ {
return GetRecordingGroupNames(recording).Select(i => i.ToLower() return GetRecordingGroupNames(recording).Select(i => i.ToLower()
.GetMD5()) .GetMD5())
@ -1795,7 +1856,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv
var groups = new List<BaseItemDto>(); var groups = new List<BaseItemDto>();
var series = recordings var series = recordings
.Where(i => i.RecordingInfo.IsSeries) .Where(i => i.IsSeries)
.ToLookup(i => i.Name, StringComparer.OrdinalIgnoreCase) .ToLookup(i => i.Name, StringComparer.OrdinalIgnoreCase)
.ToList(); .ToList();
@ -1808,31 +1869,31 @@ namespace MediaBrowser.Server.Implementations.LiveTv
groups.Add(new BaseItemDto groups.Add(new BaseItemDto
{ {
Name = "Kids", Name = "Kids",
RecordingCount = recordings.Count(i => i.RecordingInfo.IsKids) RecordingCount = recordings.Count(i => i.IsKids)
}); });
groups.Add(new BaseItemDto groups.Add(new BaseItemDto
{ {
Name = "Movies", Name = "Movies",
RecordingCount = recordings.Count(i => i.RecordingInfo.IsMovie) RecordingCount = recordings.Count(i => i.IsMovie)
}); });
groups.Add(new BaseItemDto groups.Add(new BaseItemDto
{ {
Name = "News", Name = "News",
RecordingCount = recordings.Count(i => i.RecordingInfo.IsNews) RecordingCount = recordings.Count(i => i.IsNews)
}); });
groups.Add(new BaseItemDto groups.Add(new BaseItemDto
{ {
Name = "Sports", Name = "Sports",
RecordingCount = recordings.Count(i => i.RecordingInfo.IsSports) RecordingCount = recordings.Count(i => i.IsSports)
}); });
groups.Add(new BaseItemDto groups.Add(new BaseItemDto
{ {
Name = "Others", Name = "Others",
RecordingCount = recordings.Count(i => !i.RecordingInfo.IsSports && !i.RecordingInfo.IsNews && !i.RecordingInfo.IsMovie && !i.RecordingInfo.IsKids && !i.RecordingInfo.IsSeries) RecordingCount = recordings.Count(i => !i.IsSports && !i.IsNews && !i.IsMovie && !i.IsKids && !i.IsSeries)
}); });
groups = groups groups = groups

@ -36,17 +36,17 @@ namespace MediaBrowser.Server.Implementations.LiveTv
var imageResponse = new DynamicImageResponse(); var imageResponse = new DynamicImageResponse();
if (!string.IsNullOrEmpty(liveTvItem.RecordingInfo.ImagePath)) if (!string.IsNullOrEmpty(liveTvItem.ProviderImagePath))
{ {
imageResponse.Path = liveTvItem.RecordingInfo.ImagePath; imageResponse.Path = liveTvItem.ProviderImagePath;
imageResponse.HasImage = true; imageResponse.HasImage = true;
} }
else if (!string.IsNullOrEmpty(liveTvItem.RecordingInfo.ImageUrl)) else if (!string.IsNullOrEmpty(liveTvItem.ProviderImageUrl))
{ {
var options = new HttpRequestOptions var options = new HttpRequestOptions
{ {
CancellationToken = cancellationToken, CancellationToken = cancellationToken,
Url = liveTvItem.RecordingInfo.ImageUrl Url = liveTvItem.ProviderImageUrl
}; };
var response = await _httpClient.GetResponse(options).ConfigureAwait(false); var response = await _httpClient.GetResponse(options).ConfigureAwait(false);
@ -62,7 +62,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv
_logger.Error("Provider did not return an image content type."); _logger.Error("Provider did not return an image content type.");
} }
} }
else if (liveTvItem.RecordingInfo.HasImage ?? true) else
{ {
var service = _liveTvManager.Services.FirstOrDefault(i => string.Equals(i.Name, liveTvItem.ServiceName, StringComparison.OrdinalIgnoreCase)); var service = _liveTvManager.Services.FirstOrDefault(i => string.Equals(i.Name, liveTvItem.ServiceName, StringComparison.OrdinalIgnoreCase));
@ -70,7 +70,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv
{ {
try try
{ {
var response = await service.GetRecordingImageAsync(liveTvItem.RecordingInfo.Id, cancellationToken).ConfigureAwait(false); var response = await service.GetRecordingImageAsync(liveTvItem.ExternalId, cancellationToken).ConfigureAwait(false);
if (response != null) if (response != null)
{ {
@ -109,7 +109,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv
if (liveTvItem != null) if (liveTvItem != null)
{ {
return !liveTvItem.HasImage(ImageType.Primary) && (liveTvItem.RecordingInfo.HasImage ?? true); return !liveTvItem.HasImage(ImageType.Primary) && (!string.IsNullOrWhiteSpace(liveTvItem.ProviderImagePath) || !string.IsNullOrWhiteSpace(liveTvItem.ProviderImageUrl));
} }
return false; return false;
} }

@ -759,14 +759,17 @@ namespace MediaBrowser.Server.Implementations.Persistence
whereClauses.Add("IsSports=@IsSports"); whereClauses.Add("IsSports=@IsSports");
cmd.Parameters.Add(cmd, "@IsSports", DbType.Boolean).Value = query.IsSports; cmd.Parameters.Add(cmd, "@IsSports", DbType.Boolean).Value = query.IsSports;
} }
if (query.IncludeItemTypes.Length == 1)
var includeTypes = query.IncludeItemTypes.SelectMany(MapIncludeItemTypes).ToArray();
if (includeTypes.Length == 1)
{ {
whereClauses.Add("type=@type"); whereClauses.Add("type=@type");
cmd.Parameters.Add(cmd, "@type", DbType.String).Value = MapIncludeItemType(query.IncludeItemTypes[0]); cmd.Parameters.Add(cmd, "@type", DbType.String).Value = includeTypes[0];
} }
if (query.IncludeItemTypes.Length > 1) if (includeTypes.Length > 1)
{ {
var inClause = string.Join(",", query.IncludeItemTypes.Select(i => "'" + MapIncludeItemType(i) + "'").ToArray()); var inClause = string.Join(",", includeTypes.Select(i => "'" + i + "'").ToArray());
whereClauses.Add(string.Format("type in ({0})", inClause)); whereClauses.Add(string.Format("type in ({0})", inClause));
} }
if (query.ChannelIds.Length == 1) if (query.ChannelIds.Length == 1)
@ -839,21 +842,24 @@ namespace MediaBrowser.Server.Implementations.Persistence
} }
// Not crazy about having this all the way down here, but at least it's in one place // 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) readonly Dictionary<string, string[]> _types = new Dictionary<string, string[]>(StringComparer.OrdinalIgnoreCase)
{ {
{typeof(LiveTvProgram).Name, typeof(LiveTvProgram).FullName}, {typeof(LiveTvProgram).Name, new []{typeof(LiveTvProgram).FullName}},
{typeof(LiveTvChannel).Name, typeof(LiveTvChannel).FullName} {typeof(LiveTvChannel).Name, new []{typeof(LiveTvChannel).FullName}},
{typeof(LiveTvVideoRecording).Name, new []{typeof(LiveTvVideoRecording).FullName}},
{typeof(LiveTvAudioRecording).Name, new []{typeof(LiveTvAudioRecording).FullName}},
{"Recording", new []{typeof(LiveTvAudioRecording).FullName, typeof(LiveTvVideoRecording).FullName}}
}; };
private string MapIncludeItemType(string value) private IEnumerable<string> MapIncludeItemTypes(string value)
{ {
string result; string[] result;
if (_types.TryGetValue(value, out result)) if (_types.TryGetValue(value, out result))
{ {
return result; return result;
} }
return value; return new[] { value };
} }
public IEnumerable<Guid> GetItemIdsOfType(Type type) public IEnumerable<Guid> GetItemIdsOfType(Type type)

@ -1528,16 +1528,16 @@ namespace MediaBrowser.Server.Implementations.Session
} }
var recording = item as ILiveTvRecording; var recording = item as ILiveTvRecording;
if (recording != null && recording.RecordingInfo != null) if (recording != null)
{ {
if (recording.RecordingInfo.IsSeries) if (recording.IsSeries)
{ {
info.Name = recording.RecordingInfo.EpisodeTitle; info.Name = recording.EpisodeTitle;
info.SeriesName = recording.RecordingInfo.Name; info.SeriesName = recording.Name;
if (string.IsNullOrWhiteSpace(info.Name)) if (string.IsNullOrWhiteSpace(info.Name))
{ {
info.Name = recording.RecordingInfo.Name; info.Name = recording.Name;
} }
} }
} }

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

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

@ -2,7 +2,7 @@
<package xmlns="http://schemas.microsoft.com/packaging/2011/08/nuspec.xsd"> <package xmlns="http://schemas.microsoft.com/packaging/2011/08/nuspec.xsd">
<metadata> <metadata>
<id>MediaBrowser.Model.Signed</id> <id>MediaBrowser.Model.Signed</id>
<version>3.0.622</version> <version>3.0.624</version>
<title>MediaBrowser.Model - Signed Edition</title> <title>MediaBrowser.Model - Signed Edition</title>
<authors>Emby Team</authors> <authors>Emby Team</authors>
<owners>ebr,Luke,scottisafool</owners> <owners>ebr,Luke,scottisafool</owners>

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

Loading…
Cancel
Save