aboutsummaryrefslogtreecommitdiff
path: root/MediaBrowser.Server.Implementations/LiveTv
diff options
context:
space:
mode:
Diffstat (limited to 'MediaBrowser.Server.Implementations/LiveTv')
-rw-r--r--MediaBrowser.Server.Implementations/LiveTv/EmbyTV/EmbyTV.cs171
-rw-r--r--MediaBrowser.Server.Implementations/LiveTv/EmbyTV/ItemDataProvider.cs7
-rw-r--r--MediaBrowser.Server.Implementations/LiveTv/EmbyTV/SeriesTimerManager.cs5
-rw-r--r--MediaBrowser.Server.Implementations/LiveTv/EmbyTV/TimerManager.cs5
-rw-r--r--MediaBrowser.Server.Implementations/LiveTv/Listings/SchedulesDirect.cs25
-rw-r--r--MediaBrowser.Server.Implementations/LiveTv/LiveTvManager.cs23
-rw-r--r--MediaBrowser.Server.Implementations/LiveTv/TunerHosts/BaseTunerHost.cs57
-rw-r--r--MediaBrowser.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunHost.cs16
-rw-r--r--MediaBrowser.Server.Implementations/LiveTv/TunerHosts/M3UTunerHost.cs13
9 files changed, 226 insertions, 96 deletions
diff --git a/MediaBrowser.Server.Implementations/LiveTv/EmbyTV/EmbyTV.cs b/MediaBrowser.Server.Implementations/LiveTv/EmbyTV/EmbyTV.cs
index 4e0d6e8d4..38b83eb02 100644
--- a/MediaBrowser.Server.Implementations/LiveTv/EmbyTV/EmbyTV.cs
+++ b/MediaBrowser.Server.Implementations/LiveTv/EmbyTV/EmbyTV.cs
@@ -8,7 +8,9 @@ using MediaBrowser.Controller.Drawing;
using MediaBrowser.Controller.FileOrganization;
using MediaBrowser.Controller.Library;
using MediaBrowser.Controller.LiveTv;
+using MediaBrowser.Controller.MediaEncoding;
using MediaBrowser.Controller.Providers;
+using MediaBrowser.Model.Dlna;
using MediaBrowser.Model.Dto;
using MediaBrowser.Model.Entities;
using MediaBrowser.Model.Events;
@@ -47,10 +49,11 @@ namespace MediaBrowser.Server.Implementations.LiveTv.EmbyTV
private readonly ILibraryManager _libraryManager;
private readonly IProviderManager _providerManager;
private readonly IFileOrganizationService _organizationService;
+ private readonly IMediaEncoder _mediaEncoder;
public static EmbyTV Current;
- public EmbyTV(IApplicationHost appHost, ILogger logger, IJsonSerializer jsonSerializer, IHttpClient httpClient, IServerConfigurationManager config, ILiveTvManager liveTvManager, IFileSystem fileSystem, ISecurityManager security, ILibraryManager libraryManager, ILibraryMonitor libraryMonitor, IProviderManager providerManager, IFileOrganizationService organizationService)
+ public EmbyTV(IApplicationHost appHost, ILogger logger, IJsonSerializer jsonSerializer, IHttpClient httpClient, IServerConfigurationManager config, ILiveTvManager liveTvManager, IFileSystem fileSystem, ISecurityManager security, ILibraryManager libraryManager, ILibraryMonitor libraryMonitor, IProviderManager providerManager, IFileOrganizationService organizationService, IMediaEncoder mediaEncoder)
{
Current = this;
@@ -64,12 +67,13 @@ namespace MediaBrowser.Server.Implementations.LiveTv.EmbyTV
_libraryMonitor = libraryMonitor;
_providerManager = providerManager;
_organizationService = organizationService;
+ _mediaEncoder = mediaEncoder;
_liveTvManager = (LiveTvManager)liveTvManager;
_jsonSerializer = jsonSerializer;
- _recordingProvider = new ItemDataProvider<RecordingInfo>(jsonSerializer, _logger, Path.Combine(DataPath, "recordings"), (r1, r2) => string.Equals(r1.Id, r2.Id, StringComparison.OrdinalIgnoreCase));
- _seriesTimerProvider = new SeriesTimerManager(jsonSerializer, _logger, Path.Combine(DataPath, "seriestimers"));
- _timerProvider = new TimerManager(jsonSerializer, _logger, Path.Combine(DataPath, "timers"));
+ _recordingProvider = new ItemDataProvider<RecordingInfo>(fileSystem, jsonSerializer, _logger, Path.Combine(DataPath, "recordings"), (r1, r2) => string.Equals(r1.Id, r2.Id, StringComparison.OrdinalIgnoreCase));
+ _seriesTimerProvider = new SeriesTimerManager(fileSystem, jsonSerializer, _logger, Path.Combine(DataPath, "seriestimers"));
+ _timerProvider = new TimerManager(fileSystem, jsonSerializer, _logger, Path.Combine(DataPath, "timers"));
_timerProvider.TimerFired += _timerProvider_TimerFired;
}
@@ -126,6 +130,33 @@ namespace MediaBrowser.Server.Implementations.LiveTv.EmbyTV
return status;
}
+ public async Task RefreshSeriesTimers(CancellationToken cancellationToken, IProgress<double> progress)
+ {
+ var timers = await GetSeriesTimersAsync(cancellationToken).ConfigureAwait(false);
+
+ List<ChannelInfo> channels = null;
+
+ foreach (var timer in timers)
+ {
+ List<ProgramInfo> epgData;
+
+ if (timer.RecordAnyChannel)
+ {
+ if (channels == null)
+ {
+ channels = (await GetChannelsAsync(true, CancellationToken.None).ConfigureAwait(false)).ToList();
+ }
+ var channelIds = channels.Select(i => i.Id).ToList();
+ epgData = GetEpgDataForChannels(channelIds);
+ }
+ else
+ {
+ epgData = GetEpgDataForChannel(timer.ChannelId);
+ }
+ await UpdateTimersForSeriesTimer(epgData, timer).ConfigureAwait(false);
+ }
+ }
+
private List<ChannelInfo> _channelCache = null;
private async Task<IEnumerable<ChannelInfo>> GetChannelsAsync(bool enableCache, CancellationToken cancellationToken)
{
@@ -235,7 +266,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv.EmbyTV
try
{
- File.Delete(remove.Path);
+ _fileSystem.DeleteFile(remove.Path);
}
catch (DirectoryNotFoundException)
{
@@ -366,6 +397,19 @@ namespace MediaBrowser.Server.Implementations.LiveTv.EmbyTV
public async Task<IEnumerable<ProgramInfo>> GetProgramsAsync(string channelId, DateTime startDateUtc, DateTime endDateUtc, CancellationToken cancellationToken)
{
+ try
+ {
+ return await GetProgramsAsyncInternal(channelId, startDateUtc, endDateUtc, cancellationToken).ConfigureAwait(false);
+ }
+ catch (Exception ex)
+ {
+ _logger.ErrorException("Error getting programs", ex);
+ return GetEpgDataForChannel(channelId).Where(i => i.StartDate <= endDateUtc && i.EndDate >= startDateUtc);
+ }
+ }
+
+ private async Task<IEnumerable<ProgramInfo>> GetProgramsAsyncInternal(string channelId, DateTime startDateUtc, DateTime endDateUtc, CancellationToken cancellationToken)
+ {
var channels = await GetChannelsAsync(true, cancellationToken).ConfigureAwait(false);
var channel = channels.First(i => string.Equals(i.Id, channelId, StringComparison.OrdinalIgnoreCase));
@@ -373,6 +417,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv.EmbyTV
{
var programs = await provider.Item1.GetProgramsAsync(provider.Item2, channel.Number, startDateUtc, endDateUtc, cancellationToken)
.ConfigureAwait(false);
+
var list = programs.ToList();
// Replace the value that came from the provider with a normalized value
@@ -428,6 +473,8 @@ namespace MediaBrowser.Server.Implementations.LiveTv.EmbyTV
if (mediaSourceInfo != null)
{
+ await AddMediaInfo(mediaSourceInfo, false, cancellationToken).ConfigureAwait(false);
+
mediaSourceInfo.Id = Guid.NewGuid().ToString("N");
return mediaSourceInfo;
}
@@ -458,6 +505,84 @@ namespace MediaBrowser.Server.Implementations.LiveTv.EmbyTV
throw new NotImplementedException();
}
+ private async Task AddMediaInfo(MediaSourceInfo mediaSource, bool isAudio, CancellationToken cancellationToken)
+ {
+ var originalRuntime = mediaSource.RunTimeTicks;
+
+ var info = await _mediaEncoder.GetMediaInfo(new MediaInfoRequest
+ {
+ InputPath = mediaSource.Path,
+ Protocol = mediaSource.Protocol,
+ MediaType = isAudio ? DlnaProfileType.Audio : DlnaProfileType.Video,
+ ExtractChapters = false
+
+ }, cancellationToken).ConfigureAwait(false);
+
+ mediaSource.Bitrate = info.Bitrate;
+ mediaSource.Container = info.Container;
+ mediaSource.Formats = info.Formats;
+ mediaSource.MediaStreams = info.MediaStreams;
+ mediaSource.RunTimeTicks = info.RunTimeTicks;
+ mediaSource.Size = info.Size;
+ mediaSource.Timestamp = info.Timestamp;
+ mediaSource.Video3DFormat = info.Video3DFormat;
+ mediaSource.VideoType = info.VideoType;
+
+ mediaSource.DefaultSubtitleStreamIndex = null;
+
+ // Null this out so that it will be treated like a live stream
+ if (!originalRuntime.HasValue)
+ {
+ mediaSource.RunTimeTicks = null;
+ }
+
+ var audioStream = mediaSource.MediaStreams.FirstOrDefault(i => i.Type == Model.Entities.MediaStreamType.Audio);
+
+ if (audioStream == null || audioStream.Index == -1)
+ {
+ mediaSource.DefaultAudioStreamIndex = null;
+ }
+ else
+ {
+ mediaSource.DefaultAudioStreamIndex = audioStream.Index;
+ }
+
+ var videoStream = mediaSource.MediaStreams.FirstOrDefault(i => i.Type == Model.Entities.MediaStreamType.Video);
+ if (videoStream != null)
+ {
+ if (!videoStream.BitRate.HasValue)
+ {
+ var width = videoStream.Width ?? 1920;
+
+ if (width >= 1900)
+ {
+ videoStream.BitRate = 8000000;
+ }
+
+ else if (width >= 1260)
+ {
+ videoStream.BitRate = 3000000;
+ }
+
+ else if (width >= 700)
+ {
+ videoStream.BitRate = 1000000;
+ }
+ }
+ }
+
+ // Try to estimate this
+ if (!mediaSource.Bitrate.HasValue)
+ {
+ var total = mediaSource.MediaStreams.Select(i => i.BitRate ?? 0).Sum();
+
+ if (total > 0)
+ {
+ mediaSource.Bitrate = total;
+ }
+ }
+ }
+
public Task<List<MediaSourceInfo>> GetRecordingStreamMediaSources(string recordingId, CancellationToken cancellationToken)
{
throw new NotImplementedException();
@@ -500,14 +625,6 @@ namespace MediaBrowser.Server.Implementations.LiveTv.EmbyTV
catch (Exception ex)
{
_logger.ErrorException("Error recording stream", ex);
-
- if (DateTime.UtcNow < timer.EndDate)
- {
- const int retryIntervalSeconds = 60;
- _logger.Info("Retrying recording in {0} seconds.", retryIntervalSeconds);
-
- _timerProvider.StartTimer(timer, TimeSpan.FromSeconds(retryIntervalSeconds));
- }
}
}
@@ -553,7 +670,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv.EmbyTV
var recordingFileName = _fileSystem.GetValidFilename(RecordingHelper.GetRecordingName(timer, info)) + ".ts";
recordPath = Path.Combine(recordPath, recordingFileName);
- Directory.CreateDirectory(Path.GetDirectoryName(recordPath));
+ _fileSystem.CreateDirectory(Path.GetDirectoryName(recordPath));
var recording = _recordingProvider.GetAll().FirstOrDefault(x => string.Equals(x.ProgramId, info.Id, StringComparison.OrdinalIgnoreCase));
@@ -597,7 +714,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv.EmbyTV
_recordingProvider.Update(recording);
_logger.Info("Beginning recording.");
-
+
try
{
httpRequestOptions.BufferContent = false;
@@ -607,7 +724,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv.EmbyTV
_logger.Info("Writing file to path: " + recordPath);
using (var response = await _httpClient.SendAsync(httpRequestOptions, "GET"))
{
- using (var output = File.Open(recordPath, FileMode.Create, FileAccess.Write, FileShare.Read))
+ using (var output = _fileSystem.GetFileStream(recordPath, FileMode.Create, FileAccess.Write, FileShare.Read))
{
await response.Content.CopyToAsync(output, StreamDefaults.DefaultCopyToBufferSize, linkedToken);
}
@@ -626,15 +743,31 @@ namespace MediaBrowser.Server.Implementations.LiveTv.EmbyTV
_logger.ErrorException("Error recording", ex);
recording.Status = RecordingStatus.Error;
}
+ finally
+ {
+ CancellationTokenSource removed;
+ _activeRecordings.TryRemove(timer.Id, out removed);
+ }
recording.DateLastUpdated = DateTime.UtcNow;
_recordingProvider.Update(recording);
- _timerProvider.Delete(timer);
- _logger.Info("Recording was a success");
if (recording.Status == RecordingStatus.Completed)
{
OnSuccessfulRecording(recording);
+ _timerProvider.Delete(timer);
+ }
+ else if (DateTime.UtcNow < timer.EndDate)
+ {
+ const int retryIntervalSeconds = 60;
+ _logger.Info("Retrying recording in {0} seconds.", retryIntervalSeconds);
+
+ _timerProvider.StartTimer(timer, TimeSpan.FromSeconds(retryIntervalSeconds));
+ }
+ else
+ {
+ _timerProvider.Delete(timer);
+ _recordingProvider.Delete(recording);
}
}
@@ -752,7 +885,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv.EmbyTV
private void SaveEpgDataForChannel(string channelId, List<ProgramInfo> epgData)
{
var path = GetChannelEpgCachePath(channelId);
- Directory.CreateDirectory(Path.GetDirectoryName(path));
+ _fileSystem.CreateDirectory(Path.GetDirectoryName(path));
lock (_epgLock)
{
_jsonSerializer.SerializeToFile(epgData, path);
diff --git a/MediaBrowser.Server.Implementations/LiveTv/EmbyTV/ItemDataProvider.cs b/MediaBrowser.Server.Implementations/LiveTv/EmbyTV/ItemDataProvider.cs
index 75dec5f97..2c8917ab4 100644
--- a/MediaBrowser.Server.Implementations/LiveTv/EmbyTV/ItemDataProvider.cs
+++ b/MediaBrowser.Server.Implementations/LiveTv/EmbyTV/ItemDataProvider.cs
@@ -4,6 +4,7 @@ using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
+using MediaBrowser.Common.IO;
namespace MediaBrowser.Server.Implementations.LiveTv.EmbyTV
{
@@ -16,13 +17,15 @@ namespace MediaBrowser.Server.Implementations.LiveTv.EmbyTV
protected readonly ILogger Logger;
private readonly string _dataPath;
protected readonly Func<T, T, bool> EqualityComparer;
+ private readonly IFileSystem _fileSystem;
- public ItemDataProvider(IJsonSerializer jsonSerializer, ILogger logger, string dataPath, Func<T, T, bool> equalityComparer)
+ public ItemDataProvider(IFileSystem fileSystem, IJsonSerializer jsonSerializer, ILogger logger, string dataPath, Func<T, T, bool> equalityComparer)
{
Logger = logger;
_dataPath = dataPath;
EqualityComparer = equalityComparer;
_jsonSerializer = jsonSerializer;
+ _fileSystem = fileSystem;
}
public IReadOnlyList<T> GetAll()
@@ -69,7 +72,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv.EmbyTV
private void UpdateList(List<T> newList)
{
var file = _dataPath + ".json";
- Directory.CreateDirectory(Path.GetDirectoryName(file));
+ _fileSystem.CreateDirectory(Path.GetDirectoryName(file));
lock (_fileDataLock)
{
diff --git a/MediaBrowser.Server.Implementations/LiveTv/EmbyTV/SeriesTimerManager.cs b/MediaBrowser.Server.Implementations/LiveTv/EmbyTV/SeriesTimerManager.cs
index eab278eb4..563658885 100644
--- a/MediaBrowser.Server.Implementations/LiveTv/EmbyTV/SeriesTimerManager.cs
+++ b/MediaBrowser.Server.Implementations/LiveTv/EmbyTV/SeriesTimerManager.cs
@@ -2,13 +2,14 @@
using MediaBrowser.Model.Logging;
using MediaBrowser.Model.Serialization;
using System;
+using MediaBrowser.Common.IO;
namespace MediaBrowser.Server.Implementations.LiveTv.EmbyTV
{
public class SeriesTimerManager : ItemDataProvider<SeriesTimerInfo>
{
- public SeriesTimerManager(IJsonSerializer jsonSerializer, ILogger logger, string dataPath)
- : base(jsonSerializer, logger, dataPath, (r1, r2) => string.Equals(r1.Id, r2.Id, StringComparison.OrdinalIgnoreCase))
+ public SeriesTimerManager(IFileSystem fileSystem, IJsonSerializer jsonSerializer, ILogger logger, string dataPath)
+ : base(fileSystem, jsonSerializer, logger, dataPath, (r1, r2) => string.Equals(r1.Id, r2.Id, StringComparison.OrdinalIgnoreCase))
{
}
diff --git a/MediaBrowser.Server.Implementations/LiveTv/EmbyTV/TimerManager.cs b/MediaBrowser.Server.Implementations/LiveTv/EmbyTV/TimerManager.cs
index 3ae38f382..64a5b7339 100644
--- a/MediaBrowser.Server.Implementations/LiveTv/EmbyTV/TimerManager.cs
+++ b/MediaBrowser.Server.Implementations/LiveTv/EmbyTV/TimerManager.cs
@@ -7,6 +7,7 @@ using System;
using System.Collections.Concurrent;
using System.Linq;
using System.Threading;
+using MediaBrowser.Common.IO;
namespace MediaBrowser.Server.Implementations.LiveTv.EmbyTV
{
@@ -16,8 +17,8 @@ namespace MediaBrowser.Server.Implementations.LiveTv.EmbyTV
public event EventHandler<GenericEventArgs<TimerInfo>> TimerFired;
- public TimerManager(IJsonSerializer jsonSerializer, ILogger logger, string dataPath)
- : base(jsonSerializer, logger, dataPath, (r1, r2) => string.Equals(r1.Id, r2.Id, StringComparison.OrdinalIgnoreCase))
+ public TimerManager(IFileSystem fileSystem, IJsonSerializer jsonSerializer, ILogger logger, string dataPath)
+ : base(fileSystem, jsonSerializer, logger, dataPath, (r1, r2) => string.Equals(r1.Id, r2.Id, StringComparison.OrdinalIgnoreCase))
{
}
diff --git a/MediaBrowser.Server.Implementations/LiveTv/Listings/SchedulesDirect.cs b/MediaBrowser.Server.Implementations/LiveTv/Listings/SchedulesDirect.cs
index d53c08150..868889ba7 100644
--- a/MediaBrowser.Server.Implementations/LiveTv/Listings/SchedulesDirect.cs
+++ b/MediaBrowser.Server.Implementations/LiveTv/Listings/SchedulesDirect.cs
@@ -216,20 +216,12 @@ namespace MediaBrowser.Server.Implementations.LiveTv.Listings
// Helper.logger.Info("Modifyin channel " + channel.Number);
if (_channelPair.ContainsKey(channel.Number))
{
- string channelName;
if (_channelPair[channel.Number].logo != null)
{
channel.ImageUrl = _channelPair[channel.Number].logo.URL;
channel.HasImage = true;
}
- if (_channelPair[channel.Number].affiliate != null)
- {
- channelName = _channelPair[channel.Number].affiliate;
- }
- else
- {
- channelName = _channelPair[channel.Number].name;
- }
+ string channelName = _channelPair[channel.Number].name;
channel.Name = channelName;
}
else
@@ -245,8 +237,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv.Listings
ScheduleDirect.ProgramDetails details)
{
//_logger.Debug("Show type is: " + (details.showType ?? "No ShowType"));
- DateTime startAt = DateTime.ParseExact(programInfo.airDateTime, "yyyy'-'MM'-'dd'T'HH':'mm':'ss'Z'",
- CultureInfo.InvariantCulture);
+ DateTime startAt = GetDate(programInfo.airDateTime);
DateTime endAt = startAt.AddSeconds(programInfo.duration);
ProgramAudio audioType = ProgramAudio.Stereo;
@@ -369,6 +360,17 @@ namespace MediaBrowser.Server.Implementations.LiveTv.Listings
return info;
}
+ private DateTime GetDate(string value)
+ {
+ var date = DateTime.ParseExact(value, "yyyy'-'MM'-'dd'T'HH':'mm':'ss'Z'", CultureInfo.InvariantCulture);
+
+ if (date.Kind != DateTimeKind.Utc)
+ {
+ date = DateTime.SpecifyKind(date, DateTimeKind.Utc);
+ }
+ return date;
+ }
+
private string GetProgramLogo(string apiUrl, ScheduleDirect.ShowImages images)
{
string url = "";
@@ -408,7 +410,6 @@ namespace MediaBrowser.Server.Implementations.LiveTv.Listings
{
imageIdString += "\"" + i.Substring(0, 10) + "\",";
}
- ;
});
imageIdString = imageIdString.TrimEnd(',') + "]";
diff --git a/MediaBrowser.Server.Implementations/LiveTv/LiveTvManager.cs b/MediaBrowser.Server.Implementations/LiveTv/LiveTvManager.cs
index d73b144b8..0a33d7383 100644
--- a/MediaBrowser.Server.Implementations/LiveTv/LiveTvManager.cs
+++ b/MediaBrowser.Server.Implementations/LiveTv/LiveTvManager.cs
@@ -580,7 +580,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv
item.Name = channelInfo.Name;
}
- await item.RefreshMetadata(new MetadataRefreshOptions
+ await item.RefreshMetadata(new MetadataRefreshOptions(_fileSystem)
{
ForceSave = isNew,
ReplaceImages = replaceImages.Distinct().ToList()
@@ -659,7 +659,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv
}
}
- _providerManager.QueueRefresh(item.Id, new MetadataRefreshOptions());
+ _providerManager.QueueRefresh(item.Id, new MetadataRefreshOptions(_fileSystem));
return item;
}
@@ -759,7 +759,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv
await _libraryManager.UpdateItem(item, ItemUpdateType.MetadataImport, cancellationToken).ConfigureAwait(false);
}
- _providerManager.QueueRefresh(item.Id, new MetadataRefreshOptions());
+ _providerManager.QueueRefresh(item.Id, new MetadataRefreshOptions(_fileSystem));
return item.Id;
}
@@ -1082,6 +1082,13 @@ namespace MediaBrowser.Server.Implementations.LiveTv
await CleanDatabaseInternal(newChannelIdList, new[] { typeof(LiveTvChannel).Name }, progress, cancellationToken).ConfigureAwait(false);
await CleanDatabaseInternal(newProgramIdList, new[] { typeof(LiveTvProgram).Name }, progress, cancellationToken).ConfigureAwait(false);
+ var coreService = _services.OfType<EmbyTV.EmbyTV>().FirstOrDefault();
+
+ if (coreService != null)
+ {
+ await coreService.RefreshSeriesTimers(cancellationToken, new Progress<double>()).ConfigureAwait(false);
+ }
+
// Load these now which will prefetch metadata
var dtoOptions = new DtoOptions();
dtoOptions.Fields.Remove(ItemFields.SyncInfo);
@@ -1155,7 +1162,17 @@ namespace MediaBrowser.Server.Implementations.LiveTv
foreach (var program in channelPrograms)
{
+ if (program.StartDate.Kind != DateTimeKind.Utc)
+ {
+ _logger.Error("{0} returned StartDate.DateTimeKind.{1} instead of UTC for program {2}", service.Name, program.StartDate.Kind.ToString(), program.Name);
+ }
+ else if (program.EndDate.Kind != DateTimeKind.Utc)
+ {
+ _logger.Error("{0} returned EndDate.DateTimeKind.{1} instead of UTC for program {2}", service.Name, program.EndDate.Kind.ToString(), program.Name);
+ }
+
var programItem = await GetProgram(program, channelId, currentChannel.ChannelType, service.Name, cancellationToken).ConfigureAwait(false);
+
programs.Add(programItem.Id);
}
}
diff --git a/MediaBrowser.Server.Implementations/LiveTv/TunerHosts/BaseTunerHost.cs b/MediaBrowser.Server.Implementations/LiveTv/TunerHosts/BaseTunerHost.cs
index 909e2bba5..e5222e55d 100644
--- a/MediaBrowser.Server.Implementations/LiveTv/TunerHosts/BaseTunerHost.cs
+++ b/MediaBrowser.Server.Implementations/LiveTv/TunerHosts/BaseTunerHost.cs
@@ -109,23 +109,22 @@ namespace MediaBrowser.Server.Implementations.LiveTv.TunerHosts
foreach (var host in hostsWithChannel)
{
- // Check to make sure the tuner is available
- // If there's only one tuner, don't bother with the check and just let the tuner be the one to throw an error
- if (hostsWithChannel.Count > 1 && !await IsAvailable(host, channelId, cancellationToken).ConfigureAwait(false))
+ try
{
- Logger.Error("Tuner is not currently available");
- continue;
- }
+ var mediaSources = await GetChannelStreamMediaSources(host, channelId, cancellationToken).ConfigureAwait(false);
- var mediaSources = await GetChannelStreamMediaSources(host, channelId, cancellationToken).ConfigureAwait(false);
+ // Prefix the id with the host Id so that we can easily find it
+ foreach (var mediaSource in mediaSources)
+ {
+ mediaSource.Id = host.Id + mediaSource.Id;
+ }
- // Prefix the id with the host Id so that we can easily find it
- foreach (var mediaSource in mediaSources)
+ return mediaSources;
+ }
+ catch (Exception ex)
{
- mediaSource.Id = host.Id + mediaSource.Id;
+ Logger.Error("Error opening tuner", ex);
}
-
- return mediaSources;
}
}
@@ -163,23 +162,18 @@ namespace MediaBrowser.Server.Implementations.LiveTv.TunerHosts
foreach (var host in hostsWithChannel)
{
- // Check to make sure the tuner is available
- // If there's only one tuner, don't bother with the check and just let the tuner be the one to throw an error
- // If a streamId is specified then availibility has already been checked in GetChannelStreamMediaSources
- if (string.IsNullOrWhiteSpace(streamId) && hostsWithChannel.Count > 1)
+ try
{
- if (!await IsAvailable(host, channelId, cancellationToken).ConfigureAwait(false))
+ var stream = await GetChannelStream(host, channelId, streamId, cancellationToken).ConfigureAwait(false);
+
+ if (stream != null)
{
- Logger.Error("Tuner is not currently available");
- continue;
+ return stream;
}
}
-
- var stream = await GetChannelStream(host, channelId, streamId, cancellationToken).ConfigureAwait(false);
-
- if (stream != null)
+ catch (Exception ex)
{
- return stream;
+ Logger.Error("Error opening tuner", ex);
}
}
}
@@ -187,21 +181,6 @@ namespace MediaBrowser.Server.Implementations.LiveTv.TunerHosts
throw new LiveTvConflictException();
}
- protected async Task<bool> IsAvailable(TunerHostInfo tuner, string channelId, CancellationToken cancellationToken)
- {
- try
- {
- return await IsAvailableInternal(tuner, channelId, cancellationToken).ConfigureAwait(false);
- }
- catch (Exception ex)
- {
- Logger.ErrorException("Error checking tuner availability", ex);
- return false;
- }
- }
-
- protected abstract Task<bool> IsAvailableInternal(TunerHostInfo tuner, string channelId, CancellationToken cancellationToken);
-
protected abstract bool IsValidChannelId(string channelId);
protected LiveTvOptions GetConfiguration()
diff --git a/MediaBrowser.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunHost.cs b/MediaBrowser.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunHost.cs
index bccb0db0a..571b00257 100644
--- a/MediaBrowser.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunHost.cs
+++ b/MediaBrowser.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunHost.cs
@@ -325,11 +325,14 @@ namespace MediaBrowser.Server.Implementations.LiveTv.TunerHosts.HdHomerun
BitRate = 128000
}
},
- RequiresOpening = false,
- RequiresClosing = false,
+ RequiresOpening = true,
+ RequiresClosing = true,
BufferMs = 1000,
Container = "ts",
- Id = profile
+ Id = profile,
+ SupportsDirectPlay = true,
+ SupportsDirectStream = true,
+ SupportsTranscoding = true
};
return mediaSource;
@@ -395,12 +398,5 @@ namespace MediaBrowser.Server.Implementations.LiveTv.TunerHosts.HdHomerun
await GetChannels(info, false, CancellationToken.None).ConfigureAwait(false);
}
}
-
- protected override async Task<bool> IsAvailableInternal(TunerHostInfo tuner, string channelId, CancellationToken cancellationToken)
- {
- var info = await GetTunerInfos(tuner, cancellationToken).ConfigureAwait(false);
-
- return info.Any(i => i.Status == LiveTvTunerStatus.Available || string.Equals(i.ChannelId, channelId, StringComparison.OrdinalIgnoreCase));
- }
}
}
diff --git a/MediaBrowser.Server.Implementations/LiveTv/TunerHosts/M3UTunerHost.cs b/MediaBrowser.Server.Implementations/LiveTv/TunerHosts/M3UTunerHost.cs
index 3783e4b08..31139b15d 100644
--- a/MediaBrowser.Server.Implementations/LiveTv/TunerHosts/M3UTunerHost.cs
+++ b/MediaBrowser.Server.Implementations/LiveTv/TunerHosts/M3UTunerHost.cs
@@ -12,14 +12,18 @@ using System.IO;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
+using MediaBrowser.Common.IO;
namespace MediaBrowser.Server.Implementations.LiveTv.TunerHosts
{
public class M3UTunerHost : BaseTunerHost, ITunerHost
{
- public M3UTunerHost(IConfigurationManager config, ILogger logger)
+ private readonly IFileSystem _fileSystem;
+
+ public M3UTunerHost(IConfigurationManager config, ILogger logger, IFileSystem fileSystem)
: base(config, logger)
{
+ _fileSystem = fileSystem;
}
public override string Type
@@ -119,7 +123,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv.TunerHosts
public async Task Validate(TunerHostInfo info)
{
- if (!File.Exists(info.Url))
+ if (!_fileSystem.FileExists(info.Url))
{
throw new FileNotFoundException();
}
@@ -190,10 +194,5 @@ namespace MediaBrowser.Server.Implementations.LiveTv.TunerHosts
}
return new List<MediaSourceInfo> { };
}
-
- protected override Task<bool> IsAvailableInternal(TunerHostInfo tuner, string channelId, CancellationToken cancellationToken)
- {
- return Task.FromResult(true);
- }
}
}