aboutsummaryrefslogtreecommitdiff
path: root/MediaBrowser.Controller/LiveTv
diff options
context:
space:
mode:
Diffstat (limited to 'MediaBrowser.Controller/LiveTv')
-rw-r--r--MediaBrowser.Controller/LiveTv/ChannelInfo.cs74
-rw-r--r--MediaBrowser.Controller/LiveTv/IListingsProvider.cs19
-rw-r--r--MediaBrowser.Controller/LiveTv/ILiveTvManager.cs293
-rw-r--r--MediaBrowser.Controller/LiveTv/ILiveTvService.cs190
-rw-r--r--MediaBrowser.Controller/LiveTv/ITunerHost.cs62
-rw-r--r--MediaBrowser.Controller/LiveTv/LiveTvChannel.cs197
-rw-r--r--MediaBrowser.Controller/LiveTv/LiveTvConflictException.cs20
-rw-r--r--MediaBrowser.Controller/LiveTv/LiveTvProgram.cs349
-rw-r--r--MediaBrowser.Controller/LiveTv/LiveTvServiceStatusInfo.cs49
-rw-r--r--MediaBrowser.Controller/LiveTv/LiveTvTunerInfo.cs73
-rw-r--r--MediaBrowser.Controller/LiveTv/ProgramInfo.cs213
-rw-r--r--MediaBrowser.Controller/LiveTv/RecordingInfo.cs205
-rw-r--r--MediaBrowser.Controller/LiveTv/RecordingStatusChangedEventArgs.cs12
-rw-r--r--MediaBrowser.Controller/LiveTv/SeriesTimerInfo.cs119
-rw-r--r--MediaBrowser.Controller/LiveTv/TimerEventInfo.cs10
-rw-r--r--MediaBrowser.Controller/LiveTv/TimerInfo.cs175
-rw-r--r--MediaBrowser.Controller/LiveTv/TunerChannelMapping.cs10
17 files changed, 2070 insertions, 0 deletions
diff --git a/MediaBrowser.Controller/LiveTv/ChannelInfo.cs b/MediaBrowser.Controller/LiveTv/ChannelInfo.cs
new file mode 100644
index 000000000..c000da852
--- /dev/null
+++ b/MediaBrowser.Controller/LiveTv/ChannelInfo.cs
@@ -0,0 +1,74 @@
+using MediaBrowser.Model.LiveTv;
+
+namespace MediaBrowser.Controller.LiveTv
+{
+ /// <summary>
+ /// Class ChannelInfo
+ /// </summary>
+ public class ChannelInfo
+ {
+ /// <summary>
+ /// Gets or sets the name.
+ /// </summary>
+ /// <value>The name.</value>
+ public string Name { get; set; }
+
+ /// <summary>
+ /// Gets or sets the number.
+ /// </summary>
+ /// <value>The number.</value>
+ public string Number { get; set; }
+
+ /// <summary>
+ /// Get or sets the Id.
+ /// </summary>
+ /// <value>The id of the channel.</value>
+ public string Id { get; set; }
+
+ public string Path { get; set; }
+
+ public string TunerChannelId { get; set; }
+
+ public string CallSign { get; set; }
+
+ /// <summary>
+ /// Gets or sets the tuner host identifier.
+ /// </summary>
+ /// <value>The tuner host identifier.</value>
+ public string TunerHostId { get; set; }
+
+ /// <summary>
+ /// Gets or sets the type of the channel.
+ /// </summary>
+ /// <value>The type of the channel.</value>
+ public ChannelType ChannelType { get; set; }
+
+ /// <summary>
+ /// Supply the image path if it can be accessed directly from the file system
+ /// </summary>
+ /// <value>The image path.</value>
+ public string ImagePath { get; set; }
+
+ /// <summary>
+ /// Supply the image url if it can be downloaded
+ /// </summary>
+ /// <value>The image URL.</value>
+ public string ImageUrl { get; set; }
+
+ /// <summary>
+ /// Gets or sets a value indicating whether this instance has image.
+ /// </summary>
+ /// <value><c>null</c> if [has image] contains no value, <c>true</c> if [has image]; otherwise, <c>false</c>.</value>
+ public bool? HasImage { get; set; }
+ /// <summary>
+ /// Gets or sets a value indicating whether this instance is favorite.
+ /// </summary>
+ /// <value><c>null</c> if [is favorite] contains no value, <c>true</c> if [is favorite]; otherwise, <c>false</c>.</value>
+ public bool? IsFavorite { get; set; }
+
+ public bool? IsHD { get; set; }
+ public string AudioCodec { get; set; }
+ public string VideoCodec { get; set; }
+ public string[] Tags { get; set; }
+ }
+}
diff --git a/MediaBrowser.Controller/LiveTv/IListingsProvider.cs b/MediaBrowser.Controller/LiveTv/IListingsProvider.cs
new file mode 100644
index 000000000..faf4a34df
--- /dev/null
+++ b/MediaBrowser.Controller/LiveTv/IListingsProvider.cs
@@ -0,0 +1,19 @@
+using MediaBrowser.Model.Dto;
+using MediaBrowser.Model.LiveTv;
+using System;
+using System.Collections.Generic;
+using System.Threading;
+using System.Threading.Tasks;
+
+namespace MediaBrowser.Controller.LiveTv
+{
+ public interface IListingsProvider
+ {
+ string Name { get; }
+ string Type { get; }
+ Task<IEnumerable<ProgramInfo>> GetProgramsAsync(ListingsProviderInfo info, string channelId, DateTime startDateUtc, DateTime endDateUtc, CancellationToken cancellationToken);
+ Task Validate(ListingsProviderInfo info, bool validateLogin, bool validateListings);
+ Task<List<NameIdPair>> GetLineups(ListingsProviderInfo info, string country, string location);
+ Task<List<ChannelInfo>> GetChannels(ListingsProviderInfo info, CancellationToken cancellationToken);
+ }
+}
diff --git a/MediaBrowser.Controller/LiveTv/ILiveTvManager.cs b/MediaBrowser.Controller/LiveTv/ILiveTvManager.cs
new file mode 100644
index 000000000..a7f675034
--- /dev/null
+++ b/MediaBrowser.Controller/LiveTv/ILiveTvManager.cs
@@ -0,0 +1,293 @@
+using System;
+using MediaBrowser.Controller.Dto;
+using MediaBrowser.Controller.Entities;
+using MediaBrowser.Model.Dto;
+using MediaBrowser.Model.Entities;
+using MediaBrowser.Model.LiveTv;
+using MediaBrowser.Model.Querying;
+using System.Collections.Generic;
+using System.Threading;
+using System.Threading.Tasks;
+using MediaBrowser.Model.Events;
+using MediaBrowser.Controller.Library;
+
+namespace MediaBrowser.Controller.LiveTv
+{
+ /// <summary>
+ /// Manages all live tv services installed on the server
+ /// </summary>
+ public interface ILiveTvManager
+ {
+ /// <summary>
+ /// Gets the services.
+ /// </summary>
+ /// <value>The services.</value>
+ IReadOnlyList<ILiveTvService> Services { get; }
+
+ /// <summary>
+ /// Gets the new timer defaults asynchronous.
+ /// </summary>
+ /// <param name="cancellationToken">The cancellation token.</param>
+ /// <returns>Task{TimerInfo}.</returns>
+ Task<SeriesTimerInfoDto> GetNewTimerDefaults(CancellationToken cancellationToken);
+
+ /// <summary>
+ /// Gets the new timer defaults.
+ /// </summary>
+ /// <param name="programId">The program identifier.</param>
+ /// <param name="cancellationToken">The cancellation token.</param>
+ /// <returns>Task{SeriesTimerInfoDto}.</returns>
+ Task<SeriesTimerInfoDto> GetNewTimerDefaults(string programId, CancellationToken cancellationToken);
+
+ /// <summary>
+ /// Cancels the timer.
+ /// </summary>
+ /// <param name="id">The identifier.</param>
+ /// <returns>Task.</returns>
+ Task CancelTimer(string id);
+
+ /// <summary>
+ /// Cancels the series timer.
+ /// </summary>
+ /// <param name="id">The identifier.</param>
+ /// <returns>Task.</returns>
+ Task CancelSeriesTimer(string id);
+
+ /// <summary>
+ /// Adds the parts.
+ /// </summary>
+ /// <param name="services">The services.</param>
+ /// <param name="tunerHosts">The tuner hosts.</param>
+ /// <param name="listingProviders">The listing providers.</param>
+ void AddParts(IEnumerable<ILiveTvService> services, IEnumerable<ITunerHost> tunerHosts, IEnumerable<IListingsProvider> listingProviders);
+
+ /// <summary>
+ /// Gets the timer.
+ /// </summary>
+ /// <param name="id">The identifier.</param>
+ /// <param name="cancellationToken">The cancellation token.</param>
+ /// <returns>Task{TimerInfoDto}.</returns>
+ Task<TimerInfoDto> GetTimer(string id, CancellationToken cancellationToken);
+
+ /// <summary>
+ /// Gets the series timer.
+ /// </summary>
+ /// <param name="id">The identifier.</param>
+ /// <param name="cancellationToken">The cancellation token.</param>
+ /// <returns>Task{TimerInfoDto}.</returns>
+ Task<SeriesTimerInfoDto> GetSeriesTimer(string id, CancellationToken cancellationToken);
+
+ /// <summary>
+ /// Gets the recordings.
+ /// </summary>
+ /// <param name="query">The query.</param>
+ /// <param name="options">The options.</param>
+ QueryResult<BaseItemDto> GetRecordings(RecordingQuery query, DtoOptions options);
+
+ /// <summary>
+ /// Gets the timers.
+ /// </summary>
+ /// <param name="query">The query.</param>
+ /// <param name="cancellationToken">The cancellation token.</param>
+ /// <returns>Task{QueryResult{TimerInfoDto}}.</returns>
+ Task<QueryResult<TimerInfoDto>> GetTimers(TimerQuery query, CancellationToken cancellationToken);
+
+ /// <summary>
+ /// Gets the series timers.
+ /// </summary>
+ /// <param name="query">The query.</param>
+ /// <param name="cancellationToken">The cancellation token.</param>
+ /// <returns>Task{QueryResult{SeriesTimerInfoDto}}.</returns>
+ Task<QueryResult<SeriesTimerInfoDto>> GetSeriesTimers(SeriesTimerQuery query, CancellationToken cancellationToken);
+
+ /// <summary>
+ /// Gets the channel stream.
+ /// </summary>
+ /// <param name="id">The identifier.</param>
+ /// <param name="mediaSourceId">The media source identifier.</param>
+ /// <param name="cancellationToken">The cancellation token.</param>
+ /// <returns>Task{StreamResponseInfo}.</returns>
+ Task<Tuple<MediaSourceInfo, ILiveStream>> GetChannelStream(string id, string mediaSourceId, List<ILiveStream> currentLiveStreams, CancellationToken cancellationToken);
+
+ /// <summary>
+ /// Gets the program.
+ /// </summary>
+ /// <param name="id">The identifier.</param>
+ /// <param name="cancellationToken">The cancellation token.</param>
+ /// <param name="user">The user.</param>
+ /// <returns>Task{ProgramInfoDto}.</returns>
+ Task<BaseItemDto> GetProgram(string id, CancellationToken cancellationToken, User user = null);
+
+ /// <summary>
+ /// Gets the programs.
+ /// </summary>
+ /// <param name="query">The query.</param>
+ /// <param name="options">The options.</param>
+ /// <param name="cancellationToken">The cancellation token.</param>
+ /// <returns>IEnumerable{ProgramInfo}.</returns>
+ Task<QueryResult<BaseItemDto>> GetPrograms(InternalItemsQuery query, DtoOptions options, CancellationToken cancellationToken);
+
+ /// <summary>
+ /// Updates the timer.
+ /// </summary>
+ /// <param name="timer">The timer.</param>
+ /// <param name="cancellationToken">The cancellation token.</param>
+ /// <returns>Task.</returns>
+ Task UpdateTimer(TimerInfoDto timer, CancellationToken cancellationToken);
+
+ /// <summary>
+ /// Updates the timer.
+ /// </summary>
+ /// <param name="timer">The timer.</param>
+ /// <param name="cancellationToken">The cancellation token.</param>
+ /// <returns>Task.</returns>
+ Task UpdateSeriesTimer(SeriesTimerInfoDto timer, CancellationToken cancellationToken);
+
+ /// <summary>
+ /// Creates the timer.
+ /// </summary>
+ /// <param name="timer">The timer.</param>
+ /// <param name="cancellationToken">The cancellation token.</param>
+ /// <returns>Task.</returns>
+ Task CreateTimer(TimerInfoDto timer, CancellationToken cancellationToken);
+
+ /// <summary>
+ /// Creates the series timer.
+ /// </summary>
+ /// <param name="timer">The timer.</param>
+ /// <param name="cancellationToken">The cancellation token.</param>
+ /// <returns>Task.</returns>
+ Task CreateSeriesTimer(SeriesTimerInfoDto timer, CancellationToken cancellationToken);
+
+ /// <summary>
+ /// Gets the guide information.
+ /// </summary>
+ /// <returns>GuideInfo.</returns>
+ GuideInfo GetGuideInfo();
+
+ /// <summary>
+ /// Gets the recommended programs.
+ /// </summary>
+ /// <param name="query">The query.</param>
+ /// <param name="options">The options.</param>
+ /// <param name="cancellationToken">The cancellation token.</param>
+ QueryResult<BaseItemDto> GetRecommendedPrograms(InternalItemsQuery query, DtoOptions options, CancellationToken cancellationToken);
+
+ /// <summary>
+ /// Gets the recommended programs internal.
+ /// </summary>
+ QueryResult<BaseItem> GetRecommendedProgramsInternal(InternalItemsQuery query, DtoOptions options, CancellationToken cancellationToken);
+
+ /// <summary>
+ /// Gets the live tv information.
+ /// </summary>
+ /// <param name="cancellationToken">The cancellation token.</param>
+ /// <returns>Task{LiveTvInfo}.</returns>
+ LiveTvInfo GetLiveTvInfo(CancellationToken cancellationToken);
+
+ /// <summary>
+ /// Resets the tuner.
+ /// </summary>
+ /// <param name="id">The identifier.</param>
+ /// <param name="cancellationToken">The cancellation token.</param>
+ /// <returns>Task.</returns>
+ Task ResetTuner(string id, CancellationToken cancellationToken);
+
+ /// <summary>
+ /// Gets the live tv folder.
+ /// </summary>
+ /// <param name="cancellationToken">The cancellation token.</param>
+ Folder GetInternalLiveTvFolder(CancellationToken cancellationToken);
+
+ /// <summary>
+ /// Gets the enabled users.
+ /// </summary>
+ /// <returns>IEnumerable{User}.</returns>
+ IEnumerable<User> GetEnabledUsers();
+
+ /// <summary>
+ /// Gets the internal channels.
+ /// </summary>
+ QueryResult<BaseItem> GetInternalChannels(LiveTvChannelQuery query, DtoOptions dtoOptions, CancellationToken cancellationToken);
+
+ /// <summary>
+ /// Gets the channel media sources.
+ /// </summary>
+ Task<IEnumerable<MediaSourceInfo>> GetChannelMediaSources(BaseItem item, CancellationToken cancellationToken);
+
+ /// <summary>
+ /// Adds the information to program dto.
+ /// </summary>
+ /// <param name="programs">The programs.</param>
+ /// <param name="fields">The fields.</param>
+ /// <param name="user">The user.</param>
+ /// <returns>Task.</returns>
+ Task AddInfoToProgramDto(List<Tuple<BaseItem, BaseItemDto>> programs, ItemFields[] fields, User user = null);
+
+ /// <summary>
+ /// Saves the tuner host.
+ /// </summary>
+ Task<TunerHostInfo> SaveTunerHost(TunerHostInfo info, bool dataSourceChanged = true);
+ /// <summary>
+ /// Saves the listing provider.
+ /// </summary>
+ /// <param name="info">The information.</param>
+ /// <param name="validateLogin">if set to <c>true</c> [validate login].</param>
+ /// <param name="validateListings">if set to <c>true</c> [validate listings].</param>
+ /// <returns>Task.</returns>
+ Task<ListingsProviderInfo> SaveListingProvider(ListingsProviderInfo info, bool validateLogin, bool validateListings);
+
+ void DeleteListingsProvider(string id);
+
+ Task<TunerChannelMapping> SetChannelMapping(string providerId, string tunerChannelNumber, string providerChannelNumber);
+
+ TunerChannelMapping GetTunerChannelMapping(ChannelInfo channel, NameValuePair[] mappings, List<ChannelInfo> providerChannels);
+
+ /// <summary>
+ /// Gets the lineups.
+ /// </summary>
+ /// <param name="providerType">Type of the provider.</param>
+ /// <param name="providerId">The provider identifier.</param>
+ /// <param name="country">The country.</param>
+ /// <param name="location">The location.</param>
+ /// <returns>Task&lt;List&lt;NameIdPair&gt;&gt;.</returns>
+ Task<List<NameIdPair>> GetLineups(string providerType, string providerId, string country, string location);
+
+ /// <summary>
+ /// Adds the channel information.
+ /// </summary>
+ /// <param name="items">The items.</param>
+ /// <param name="options">The options.</param>
+ /// <param name="user">The user.</param>
+ void AddChannelInfo(List<Tuple<BaseItemDto, LiveTvChannel>> items, DtoOptions options, User user);
+
+ Task<List<ChannelInfo>> GetChannelsForListingsProvider(string id, CancellationToken cancellationToken);
+ Task<List<ChannelInfo>> GetChannelsFromListingsProviderData(string id, CancellationToken cancellationToken);
+
+ IListingsProvider[] ListingProviders { get; }
+
+ List<NameIdPair> GetTunerHostTypes();
+ Task<List<TunerHostInfo>> DiscoverTuners(bool newDevicesOnly, CancellationToken cancellationToken);
+
+ event EventHandler<GenericEventArgs<TimerEventInfo>> SeriesTimerCancelled;
+ event EventHandler<GenericEventArgs<TimerEventInfo>> TimerCancelled;
+ event EventHandler<GenericEventArgs<TimerEventInfo>> TimerCreated;
+ event EventHandler<GenericEventArgs<TimerEventInfo>> SeriesTimerCreated;
+
+ string GetEmbyTvActiveRecordingPath(string id);
+
+ ActiveRecordingInfo GetActiveRecordingInfo(string path);
+
+ void AddInfoToRecordingDto(BaseItem item, BaseItemDto dto, ActiveRecordingInfo activeRecordingInfo, User user = null);
+
+ List<BaseItem> GetRecordingFolders(User user);
+ }
+
+ public class ActiveRecordingInfo
+ {
+ public string Id { get; set; }
+ public string Path { get; set; }
+ public TimerInfo Timer { get; set; }
+ public CancellationTokenSource CancellationTokenSource { get; set; }
+ }
+}
diff --git a/MediaBrowser.Controller/LiveTv/ILiveTvService.cs b/MediaBrowser.Controller/LiveTv/ILiveTvService.cs
new file mode 100644
index 000000000..601fb69aa
--- /dev/null
+++ b/MediaBrowser.Controller/LiveTv/ILiveTvService.cs
@@ -0,0 +1,190 @@
+using MediaBrowser.Controller.Drawing;
+using MediaBrowser.Model.Dto;
+using System;
+using System.Collections.Generic;
+using System.Threading;
+using System.Threading.Tasks;
+using MediaBrowser.Controller.Library;
+
+namespace MediaBrowser.Controller.LiveTv
+{
+ /// <summary>
+ /// Represents a single live tv back end (next pvr, media portal, etc).
+ /// </summary>
+ public interface ILiveTvService
+ {
+ /// <summary>
+ /// Occurs when [data source changed].
+ /// </summary>
+ event EventHandler DataSourceChanged;
+
+ /// <summary>
+ /// Gets the name.
+ /// </summary>
+ /// <value>The name.</value>
+ string Name { get; }
+
+ /// <summary>
+ /// Gets the home page URL.
+ /// </summary>
+ /// <value>The home page URL.</value>
+ string HomePageUrl { get; }
+
+ /// <summary>
+ /// Gets the channels async.
+ /// </summary>
+ /// <param name="cancellationToken">The cancellation token.</param>
+ /// <returns>Task{IEnumerable{ChannelInfo}}.</returns>
+ Task<IEnumerable<ChannelInfo>> GetChannelsAsync(CancellationToken cancellationToken);
+
+ /// <summary>
+ /// Cancels the timer asynchronous.
+ /// </summary>
+ /// <param name="timerId">The timer identifier.</param>
+ /// <param name="cancellationToken">The cancellation token.</param>
+ /// <returns>Task.</returns>
+ Task CancelTimerAsync(string timerId, CancellationToken cancellationToken);
+
+ /// <summary>
+ /// Cancels the series timer asynchronous.
+ /// </summary>
+ /// <param name="timerId">The timer identifier.</param>
+ /// <param name="cancellationToken">The cancellation token.</param>
+ /// <returns>Task.</returns>
+ Task CancelSeriesTimerAsync(string timerId, CancellationToken cancellationToken);
+
+ /// <summary>
+ /// Creates the timer asynchronous.
+ /// </summary>
+ /// <param name="info">The information.</param>
+ /// <param name="cancellationToken">The cancellation token.</param>
+ /// <returns>Task.</returns>
+ Task CreateTimerAsync(TimerInfo info, CancellationToken cancellationToken);
+
+ /// <summary>
+ /// Creates the series timer asynchronous.
+ /// </summary>
+ /// <param name="info">The information.</param>
+ /// <param name="cancellationToken">The cancellation token.</param>
+ /// <returns>Task.</returns>
+ Task CreateSeriesTimerAsync(SeriesTimerInfo info, CancellationToken cancellationToken);
+
+ /// <summary>
+ /// Updates the timer asynchronous.
+ /// </summary>
+ /// <param name="info">The information.</param>
+ /// <param name="cancellationToken">The cancellation token.</param>
+ /// <returns>Task.</returns>
+ Task UpdateTimerAsync(TimerInfo info, CancellationToken cancellationToken);
+
+ /// <summary>
+ /// Updates the series timer asynchronous.
+ /// </summary>
+ /// <param name="info">The information.</param>
+ /// <param name="cancellationToken">The cancellation token.</param>
+ /// <returns>Task.</returns>
+ Task UpdateSeriesTimerAsync(SeriesTimerInfo info, CancellationToken cancellationToken);
+
+ /// <summary>
+ /// Gets the recordings asynchronous.
+ /// </summary>
+ /// <param name="cancellationToken">The cancellation token.</param>
+ /// <returns>Task{IEnumerable{RecordingInfo}}.</returns>
+ Task<IEnumerable<TimerInfo>> GetTimersAsync(CancellationToken cancellationToken);
+
+ /// <summary>
+ /// Gets the new timer defaults asynchronous.
+ /// </summary>
+ /// <param name="cancellationToken">The cancellation token.</param>
+ /// <param name="program">The program.</param>
+ /// <returns>Task{SeriesTimerInfo}.</returns>
+ Task<SeriesTimerInfo> GetNewTimerDefaultsAsync(CancellationToken cancellationToken, ProgramInfo program = null);
+
+ /// <summary>
+ /// Gets the series timers asynchronous.
+ /// </summary>
+ /// <param name="cancellationToken">The cancellation token.</param>
+ /// <returns>Task{IEnumerable{SeriesTimerInfo}}.</returns>
+ Task<IEnumerable<SeriesTimerInfo>> GetSeriesTimersAsync(CancellationToken cancellationToken);
+
+ /// <summary>
+ /// Gets the programs asynchronous.
+ /// </summary>
+ /// <param name="channelId">The channel identifier.</param>
+ /// <param name="startDateUtc">The start date UTC.</param>
+ /// <param name="endDateUtc">The end date UTC.</param>
+ /// <param name="cancellationToken">The cancellation token.</param>
+ /// <returns>Task{IEnumerable{ProgramInfo}}.</returns>
+ Task<IEnumerable<ProgramInfo>> GetProgramsAsync(string channelId, DateTime startDateUtc, DateTime endDateUtc, CancellationToken cancellationToken);
+
+ /// <summary>
+ /// Gets the channel stream.
+ /// </summary>
+ /// <param name="channelId">The channel identifier.</param>
+ /// <param name="streamId">The stream identifier.</param>
+ /// <param name="cancellationToken">The cancellation token.</param>
+ /// <returns>Task{Stream}.</returns>
+ Task<MediaSourceInfo> GetChannelStream(string channelId, string streamId, CancellationToken cancellationToken);
+
+ /// <summary>
+ /// Gets the channel stream media sources.
+ /// </summary>
+ /// <param name="channelId">The channel identifier.</param>
+ /// <param name="cancellationToken">The cancellation token.</param>
+ /// <returns>Task&lt;List&lt;MediaSourceInfo&gt;&gt;.</returns>
+ Task<List<MediaSourceInfo>> GetChannelStreamMediaSources(string channelId, CancellationToken cancellationToken);
+
+ /// <summary>
+ /// Closes the live stream.
+ /// </summary>
+ /// <param name="id">The identifier.</param>
+ /// <param name="cancellationToken">The cancellation token.</param>
+ /// <returns>Task.</returns>
+ Task CloseLiveStream(string id, CancellationToken cancellationToken);
+
+ /// <summary>
+ /// Records the live stream.
+ /// </summary>
+ /// <param name="id">The identifier.</param>
+ /// <param name="cancellationToken">The cancellation token.</param>
+ /// <returns>Task.</returns>
+ Task RecordLiveStream(string id, CancellationToken cancellationToken);
+
+ /// <summary>
+ /// Resets the tuner.
+ /// </summary>
+ /// <param name="id">The identifier.</param>
+ /// <param name="cancellationToken">The cancellation token.</param>
+ /// <returns>Task.</returns>
+ Task ResetTuner(string id, CancellationToken cancellationToken);
+ }
+
+ public interface ISupportsNewTimerIds
+ {
+ /// <summary>
+ /// Creates the timer asynchronous.
+ /// </summary>
+ /// <param name="info">The information.</param>
+ /// <param name="cancellationToken">The cancellation token.</param>
+ /// <returns>Task.</returns>
+ Task<string> CreateTimer(TimerInfo info, CancellationToken cancellationToken);
+
+ /// <summary>
+ /// Creates the series timer asynchronous.
+ /// </summary>
+ /// <param name="info">The information.</param>
+ /// <param name="cancellationToken">The cancellation token.</param>
+ /// <returns>Task.</returns>
+ Task<string> CreateSeriesTimer(SeriesTimerInfo info, CancellationToken cancellationToken);
+ }
+
+ public interface ISupportsDirectStreamProvider
+ {
+ Task<ILiveStream> GetChannelStreamWithDirectStreamProvider(string channelId, string streamId, List<ILiveStream> currentLiveStreams, CancellationToken cancellationToken);
+ }
+
+ public interface ISupportsUpdatingDefaults
+ {
+ Task UpdateTimerDefaults(SeriesTimerInfo info, CancellationToken cancellationToken);
+ }
+}
diff --git a/MediaBrowser.Controller/LiveTv/ITunerHost.cs b/MediaBrowser.Controller/LiveTv/ITunerHost.cs
new file mode 100644
index 000000000..d5a0e2115
--- /dev/null
+++ b/MediaBrowser.Controller/LiveTv/ITunerHost.cs
@@ -0,0 +1,62 @@
+using MediaBrowser.Model.Dto;
+using MediaBrowser.Model.LiveTv;
+using System.Collections.Generic;
+using System.Threading;
+using System.Threading.Tasks;
+using MediaBrowser.Controller.Library;
+
+namespace MediaBrowser.Controller.LiveTv
+{
+ public interface ITunerHost
+ {
+ /// <summary>
+ /// Gets the name.
+ /// </summary>
+ /// <value>The name.</value>
+ string Name { get; }
+ /// <summary>
+ /// Gets the type.
+ /// </summary>
+ /// <value>The type.</value>
+ string Type { get; }
+ /// <summary>
+ /// Gets the channels.
+ /// </summary>
+ /// <returns>Task&lt;IEnumerable&lt;ChannelInfo&gt;&gt;.</returns>
+ Task<List<ChannelInfo>> GetChannels(bool enableCache, CancellationToken cancellationToken);
+ /// <summary>
+ /// Gets the tuner infos.
+ /// </summary>
+ /// <param name="cancellationToken">The cancellation token.</param>
+ /// <returns>Task&lt;List&lt;LiveTvTunerInfo&gt;&gt;.</returns>
+ Task<List<LiveTvTunerInfo>> GetTunerInfos(CancellationToken cancellationToken);
+ /// <summary>
+ /// Gets the channel stream.
+ /// </summary>
+ /// <param name="channelId">The channel identifier.</param>
+ /// <param name="streamId">The stream identifier.</param>
+ Task<ILiveStream> GetChannelStream(string channelId, string streamId, List<ILiveStream> currentLiveStreams, CancellationToken cancellationToken);
+ /// <summary>
+ /// Gets the channel stream media sources.
+ /// </summary>
+ /// <param name="channelId">The channel identifier.</param>
+ /// <param name="cancellationToken">The cancellation token.</param>
+ /// <returns>Task&lt;List&lt;MediaSourceInfo&gt;&gt;.</returns>
+ Task<List<MediaSourceInfo>> GetChannelStreamMediaSources(string channelId, CancellationToken cancellationToken);
+
+ Task<List<TunerHostInfo>> DiscoverDevices(int discoveryDurationMs, CancellationToken cancellationToken);
+ bool IsSupported
+ {
+ get;
+ }
+ }
+ public interface IConfigurableTunerHost
+ {
+ /// <summary>
+ /// Validates the specified information.
+ /// </summary>
+ /// <param name="info">The information.</param>
+ /// <returns>Task.</returns>
+ Task Validate(TunerHostInfo info);
+ }
+}
diff --git a/MediaBrowser.Controller/LiveTv/LiveTvChannel.cs b/MediaBrowser.Controller/LiveTv/LiveTvChannel.cs
new file mode 100644
index 000000000..9e2d29eb6
--- /dev/null
+++ b/MediaBrowser.Controller/LiveTv/LiveTvChannel.cs
@@ -0,0 +1,197 @@
+using MediaBrowser.Controller.Entities;
+using MediaBrowser.Model.Configuration;
+using MediaBrowser.Model.Dto;
+using MediaBrowser.Model.Entities;
+using MediaBrowser.Model.LiveTv;
+using MediaBrowser.Model.MediaInfo;
+using System.Collections.Generic;
+using System.Globalization;
+using MediaBrowser.Model.Serialization;
+using System;
+using System.Linq;
+
+namespace MediaBrowser.Controller.LiveTv
+{
+ public class LiveTvChannel : BaseItem, IHasMediaSources, IHasProgramAttributes
+ {
+ public override List<string> GetUserDataKeys()
+ {
+ var list = base.GetUserDataKeys();
+
+ if (!ConfigurationManager.Configuration.DisableLiveTvChannelUserDataName)
+ {
+ list.Insert(0, GetClientTypeName() + "-" + Name);
+ }
+
+ return list;
+ }
+
+ public override UnratedItem GetBlockUnratedType()
+ {
+ return UnratedItem.LiveTvChannel;
+ }
+
+ [IgnoreDataMember]
+ public override bool SupportsPositionTicksResume
+ {
+ get
+ {
+ return false;
+ }
+ }
+
+ [IgnoreDataMember]
+ public override SourceType SourceType
+ {
+ get { return SourceType.LiveTV; }
+ }
+
+ [IgnoreDataMember]
+ public override bool EnableRememberingTrackSelections
+ {
+ get
+ {
+ return false;
+ }
+ }
+
+ /// <summary>
+ /// Gets or sets the number.
+ /// </summary>
+ /// <value>The number.</value>
+ public string Number { get; set; }
+
+ /// <summary>
+ /// Gets or sets the type of the channel.
+ /// </summary>
+ /// <value>The type of the channel.</value>
+ public ChannelType ChannelType { get; set; }
+
+ [IgnoreDataMember]
+ public override LocationType LocationType
+ {
+ get
+ {
+ // TODO: This should be removed
+ return LocationType.Remote;
+ }
+ }
+
+ protected override string CreateSortName()
+ {
+ if (!string.IsNullOrEmpty(Number))
+ {
+ double number = 0;
+
+ if (double.TryParse(Number, NumberStyles.Any, CultureInfo.InvariantCulture, out number))
+ {
+ return string.Format("{0:00000.0}", number) + "-" + (Name ?? string.Empty);
+ }
+ }
+
+ return (Number ?? string.Empty) + "-" + (Name ?? string.Empty);
+ }
+
+ [IgnoreDataMember]
+ public override string MediaType
+ {
+ get
+ {
+ return ChannelType == ChannelType.Radio ? Model.Entities.MediaType.Audio : Model.Entities.MediaType.Video;
+ }
+ }
+
+ public override string GetClientTypeName()
+ {
+ return "TvChannel";
+ }
+
+ public IEnumerable<BaseItem> GetTaggedItems(IEnumerable<BaseItem> inputItems)
+ {
+ return new List<BaseItem>();
+ }
+
+ public override List<MediaSourceInfo> GetMediaSources(bool enablePathSubstitution)
+ {
+ var list = new List<MediaSourceInfo>();
+
+ var info = new MediaSourceInfo
+ {
+ Id = Id.ToString("N"),
+ Protocol = PathProtocol ?? MediaProtocol.File,
+ MediaStreams = new List<MediaStream>(),
+ Name = Name,
+ Path = Path,
+ RunTimeTicks = RunTimeTicks,
+ Type = MediaSourceType.Placeholder,
+ IsInfiniteStream = RunTimeTicks == null
+ };
+
+ list.Add(info);
+
+ return list;
+ }
+
+ public override List<MediaStream> GetMediaStreams()
+ {
+ return new List<MediaStream>();
+ }
+
+ protected override string GetInternalMetadataPath(string basePath)
+ {
+ return System.IO.Path.Combine(basePath, "livetv", Id.ToString("N"), "metadata");
+ }
+
+ public override bool CanDelete()
+ {
+ return false;
+ }
+
+ [IgnoreDataMember]
+ public bool IsMovie { get; set; }
+
+ /// <summary>
+ /// Gets or sets a value indicating whether this instance is sports.
+ /// </summary>
+ /// <value><c>true</c> if this instance is sports; otherwise, <c>false</c>.</value>
+ [IgnoreDataMember]
+ public bool IsSports { get; set; }
+
+ /// <summary>
+ /// Gets or sets a value indicating whether this instance is series.
+ /// </summary>
+ /// <value><c>true</c> if this instance is series; otherwise, <c>false</c>.</value>
+ [IgnoreDataMember]
+ public bool IsSeries { get; set; }
+
+ /// <summary>
+ /// Gets or sets a value indicating whether this instance is news.
+ /// </summary>
+ /// <value><c>true</c> if this instance is news; otherwise, <c>false</c>.</value>
+ [IgnoreDataMember]
+ public bool IsNews { get; set; }
+
+ /// <summary>
+ /// Gets or sets a value indicating whether this instance is kids.
+ /// </summary>
+ /// <value><c>true</c> if this instance is kids; otherwise, <c>false</c>.</value>
+ [IgnoreDataMember]
+ public bool IsKids
+ {
+ get
+ {
+ return Tags.Contains("Kids", StringComparer.OrdinalIgnoreCase);
+ }
+ }
+
+ [IgnoreDataMember]
+ public bool IsRepeat { get; set; }
+
+ /// <summary>
+ /// Gets or sets the episode title.
+ /// </summary>
+ /// <value>The episode title.</value>
+ [IgnoreDataMember]
+ public string EpisodeTitle { get; set; }
+ }
+}
diff --git a/MediaBrowser.Controller/LiveTv/LiveTvConflictException.cs b/MediaBrowser.Controller/LiveTv/LiveTvConflictException.cs
new file mode 100644
index 000000000..a7735ad80
--- /dev/null
+++ b/MediaBrowser.Controller/LiveTv/LiveTvConflictException.cs
@@ -0,0 +1,20 @@
+using System;
+
+namespace MediaBrowser.Controller.LiveTv
+{
+ /// <summary>
+ /// Class LiveTvConflictException.
+ /// </summary>
+ public class LiveTvConflictException : Exception
+ {
+ public LiveTvConflictException()
+ {
+
+ }
+ public LiveTvConflictException(string message)
+ : base(message)
+ {
+
+ }
+ }
+} \ No newline at end of file
diff --git a/MediaBrowser.Controller/LiveTv/LiveTvProgram.cs b/MediaBrowser.Controller/LiveTv/LiveTvProgram.cs
new file mode 100644
index 000000000..fa3aab4f2
--- /dev/null
+++ b/MediaBrowser.Controller/LiveTv/LiveTvProgram.cs
@@ -0,0 +1,349 @@
+using MediaBrowser.Controller.Entities;
+using MediaBrowser.Controller.Providers;
+using MediaBrowser.Model.Configuration;
+using MediaBrowser.Model.LiveTv;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using MediaBrowser.Common.Configuration;
+using MediaBrowser.Model.Entities;
+using MediaBrowser.Model.Providers;
+using MediaBrowser.Model.Serialization;
+
+namespace MediaBrowser.Controller.LiveTv
+{
+ public class LiveTvProgram : BaseItem, IHasLookupInfo<ItemLookupInfo>, IHasStartDate, IHasProgramAttributes
+ {
+ public LiveTvProgram()
+ {
+ IsVirtualItem = true;
+ }
+
+ public override List<string> GetUserDataKeys()
+ {
+ var list = base.GetUserDataKeys();
+
+ if (!IsSeries)
+ {
+ var key = this.GetProviderId(MetadataProviders.Imdb);
+ if (!string.IsNullOrEmpty(key))
+ {
+ list.Insert(0, key);
+ }
+
+ key = this.GetProviderId(MetadataProviders.Tmdb);
+ if (!string.IsNullOrEmpty(key))
+ {
+ list.Insert(0, key);
+ }
+ }
+ else if (!string.IsNullOrEmpty(EpisodeTitle))
+ {
+ var name = GetClientTypeName();
+
+ list.Insert(0, name + "-" + Name + (EpisodeTitle ?? string.Empty));
+ }
+
+ return list;
+ }
+
+ public static double GetDefaultPrimaryImageAspectRatio(IHasProgramAttributes item)
+ {
+ var serviceName = item.ServiceName;
+
+ if (item.IsMovie)
+ {
+ if (string.Equals(serviceName, EmbyServiceName, StringComparison.OrdinalIgnoreCase) || string.Equals(serviceName, "Next Pvr", StringComparison.OrdinalIgnoreCase))
+ {
+ double value = 2;
+ value /= 3;
+
+ return value;
+ }
+ else
+ {
+ double value = 16;
+ value /= 9;
+
+ return value;
+ }
+ }
+ else
+ {
+ if (string.Equals(serviceName, EmbyServiceName, StringComparison.OrdinalIgnoreCase) || string.Equals(serviceName, "Next Pvr", StringComparison.OrdinalIgnoreCase))
+ {
+ double value = 2;
+ value /= 3;
+
+ return value;
+ }
+ else
+ {
+ double value = 16;
+ value /= 9;
+
+ return value;
+ }
+ }
+ }
+
+ private static string EmbyServiceName = "Emby";
+ public override double GetDefaultPrimaryImageAspectRatio()
+ {
+ return GetDefaultPrimaryImageAspectRatio(this);
+ }
+
+ [IgnoreDataMember]
+ public override SourceType SourceType
+ {
+ get { return SourceType.LiveTV; }
+ }
+
+ /// <summary>
+ /// The start date of the program, in UTC.
+ /// </summary>
+ [IgnoreDataMember]
+ public DateTime StartDate { get; set; }
+
+ /// <summary>
+ /// Gets or sets a value indicating whether this instance is repeat.
+ /// </summary>
+ /// <value><c>true</c> if this instance is repeat; otherwise, <c>false</c>.</value>
+ [IgnoreDataMember]
+ public bool IsRepeat { get; set; }
+
+ /// <summary>
+ /// Gets or sets the episode title.
+ /// </summary>
+ /// <value>The episode title.</value>
+ [IgnoreDataMember]
+ public string EpisodeTitle { get; set; }
+
+ [IgnoreDataMember]
+ public string ShowId { get; set; }
+
+ /// <summary>
+ /// Gets or sets a value indicating whether this instance is movie.
+ /// </summary>
+ /// <value><c>true</c> if this instance is movie; otherwise, <c>false</c>.</value>
+ [IgnoreDataMember]
+ public bool IsMovie { get; set; }
+
+ /// <summary>
+ /// Gets or sets a value indicating whether this instance is sports.
+ /// </summary>
+ /// <value><c>true</c> if this instance is sports; otherwise, <c>false</c>.</value>
+ [IgnoreDataMember]
+ public bool IsSports
+ {
+ get
+ {
+ return Tags.Contains("Sports", StringComparer.OrdinalIgnoreCase);
+ }
+ }
+
+ /// <summary>
+ /// Gets or sets a value indicating whether this instance is series.
+ /// </summary>
+ /// <value><c>true</c> if this instance is series; otherwise, <c>false</c>.</value>
+ [IgnoreDataMember]
+ public bool IsSeries { get; set; }
+
+ /// <summary>
+ /// Gets or sets a value indicating whether this instance is live.
+ /// </summary>
+ /// <value><c>true</c> if this instance is live; otherwise, <c>false</c>.</value>
+ [IgnoreDataMember]
+ public bool IsLive
+ {
+ get
+ {
+ return Tags.Contains("Live", StringComparer.OrdinalIgnoreCase);
+ }
+ }
+
+ /// <summary>
+ /// Gets or sets a value indicating whether this instance is news.
+ /// </summary>
+ /// <value><c>true</c> if this instance is news; otherwise, <c>false</c>.</value>
+ [IgnoreDataMember]
+ public bool IsNews
+ {
+ get
+ {
+ return Tags.Contains("News", StringComparer.OrdinalIgnoreCase);
+ }
+ }
+
+ /// <summary>
+ /// Gets or sets a value indicating whether this instance is kids.
+ /// </summary>
+ /// <value><c>true</c> if this instance is kids; otherwise, <c>false</c>.</value>
+ [IgnoreDataMember]
+ public bool IsKids
+ {
+ get
+ {
+ return Tags.Contains("Kids", StringComparer.OrdinalIgnoreCase);
+ }
+ }
+
+ /// <summary>
+ /// Gets or sets a value indicating whether this instance is premiere.
+ /// </summary>
+ /// <value><c>true</c> if this instance is premiere; otherwise, <c>false</c>.</value>
+ [IgnoreDataMember]
+ public bool IsPremiere
+ {
+ get
+ {
+ return Tags.Contains("Premiere", StringComparer.OrdinalIgnoreCase);
+ }
+ }
+
+ /// <summary>
+ /// Returns the folder containing the item.
+ /// If the item is a folder, it returns the folder itself
+ /// </summary>
+ /// <value>The containing folder path.</value>
+ [IgnoreDataMember]
+ public override string ContainingFolderPath
+ {
+ get
+ {
+ return Path;
+ }
+ }
+
+ //[IgnoreDataMember]
+ //public override string MediaType
+ //{
+ // get
+ // {
+ // return ChannelType == ChannelType.TV ? Model.Entities.MediaType.Video : Model.Entities.MediaType.Audio;
+ // }
+ //}
+
+ [IgnoreDataMember]
+ public bool IsAiring
+ {
+ get
+ {
+ var now = DateTime.UtcNow;
+
+ return now >= StartDate && now < EndDate;
+ }
+ }
+
+ [IgnoreDataMember]
+ public bool HasAired
+ {
+ get
+ {
+ var now = DateTime.UtcNow;
+
+ return now >= EndDate;
+ }
+ }
+
+ public override string GetClientTypeName()
+ {
+ return "Program";
+ }
+
+ public override UnratedItem GetBlockUnratedType()
+ {
+ return UnratedItem.LiveTvProgram;
+ }
+
+ protected override string GetInternalMetadataPath(string basePath)
+ {
+ return System.IO.Path.Combine(basePath, "livetv", Id.ToString("N"));
+ }
+
+ public override bool CanDelete()
+ {
+ return false;
+ }
+
+ [IgnoreDataMember]
+ public override bool SupportsPeople
+ {
+ get
+ {
+ // Optimization
+ if (IsNews || IsSports)
+ {
+ return false;
+ }
+
+ return base.SupportsPeople;
+ }
+ }
+
+ [IgnoreDataMember]
+ public override bool SupportsAncestors
+ {
+ get
+ {
+ return false;
+ }
+ }
+
+ private LiveTvOptions GetConfiguration()
+ {
+ return ConfigurationManager.GetConfiguration<LiveTvOptions>("livetv");
+ }
+
+ private ListingsProviderInfo GetListingsProviderInfo()
+ {
+ if (string.Equals(ServiceName, "Emby", StringComparison.OrdinalIgnoreCase))
+ {
+ var config = GetConfiguration();
+
+ return config.ListingProviders.FirstOrDefault(i => !string.IsNullOrEmpty(i.MoviePrefix));
+ }
+
+ return null;
+ }
+
+ protected override string GetNameForMetadataLookup()
+ {
+ var name = base.GetNameForMetadataLookup();
+
+ var listings = GetListingsProviderInfo();
+
+ if (listings != null)
+ {
+ if (!string.IsNullOrEmpty(listings.MoviePrefix) && name.StartsWith(listings.MoviePrefix, StringComparison.OrdinalIgnoreCase))
+ {
+ name = name.Substring(listings.MoviePrefix.Length).Trim();
+ }
+ }
+
+ return name;
+ }
+
+ public override List<ExternalUrl> GetRelatedUrls()
+ {
+ var list = base.GetRelatedUrls();
+
+ var imdbId = this.GetProviderId(MetadataProviders.Imdb);
+ if (!string.IsNullOrEmpty(imdbId))
+ {
+ if (IsMovie)
+ {
+ list.Add(new ExternalUrl
+ {
+ Name = "Trakt",
+ Url = string.Format("https://trakt.tv/movies/{0}", imdbId)
+ });
+ }
+ }
+
+ return list;
+ }
+
+ public string SeriesName { get; set;}
+ }
+}
diff --git a/MediaBrowser.Controller/LiveTv/LiveTvServiceStatusInfo.cs b/MediaBrowser.Controller/LiveTv/LiveTvServiceStatusInfo.cs
new file mode 100644
index 000000000..4da238acf
--- /dev/null
+++ b/MediaBrowser.Controller/LiveTv/LiveTvServiceStatusInfo.cs
@@ -0,0 +1,49 @@
+using MediaBrowser.Model.LiveTv;
+using System.Collections.Generic;
+
+namespace MediaBrowser.Controller.LiveTv
+{
+ public class LiveTvServiceStatusInfo
+ {
+ /// <summary>
+ /// Gets or sets the status.
+ /// </summary>
+ /// <value>The status.</value>
+ public LiveTvServiceStatus Status { get; set; }
+
+ /// <summary>
+ /// Gets or sets the status message.
+ /// </summary>
+ /// <value>The status message.</value>
+ public string StatusMessage { get; set; }
+
+ /// <summary>
+ /// Gets or sets the version.
+ /// </summary>
+ /// <value>The version.</value>
+ public string Version { get; set; }
+
+ /// <summary>
+ /// Gets or sets a value indicating whether this instance has update available.
+ /// </summary>
+ /// <value><c>true</c> if this instance has update available; otherwise, <c>false</c>.</value>
+ public bool HasUpdateAvailable { get; set; }
+
+ /// <summary>
+ /// Gets or sets the tuners.
+ /// </summary>
+ /// <value>The tuners.</value>
+ public List<LiveTvTunerInfo> Tuners { get; set; }
+ /// <summary>
+ /// Gets or sets a value indicating whether this instance is visible.
+ /// </summary>
+ /// <value><c>true</c> if this instance is visible; otherwise, <c>false</c>.</value>
+ public bool IsVisible { get; set; }
+
+ public LiveTvServiceStatusInfo()
+ {
+ Tuners = new List<LiveTvTunerInfo>();
+ IsVisible = true;
+ }
+ }
+}
diff --git a/MediaBrowser.Controller/LiveTv/LiveTvTunerInfo.cs b/MediaBrowser.Controller/LiveTv/LiveTvTunerInfo.cs
new file mode 100644
index 000000000..5c001f288
--- /dev/null
+++ b/MediaBrowser.Controller/LiveTv/LiveTvTunerInfo.cs
@@ -0,0 +1,73 @@
+using MediaBrowser.Model.LiveTv;
+using System.Collections.Generic;
+
+namespace MediaBrowser.Controller.LiveTv
+{
+ public class LiveTvTunerInfo
+ {
+ /// <summary>
+ /// Gets or sets the type of the source.
+ /// </summary>
+ /// <value>The type of the source.</value>
+ public string SourceType { get; set; }
+
+ /// <summary>
+ /// Gets or sets the name.
+ /// </summary>
+ /// <value>The name.</value>
+ public string Name { get; set; }
+
+ /// <summary>
+ /// Gets or sets the identifier.
+ /// </summary>
+ /// <value>The identifier.</value>
+ public string Id { get; set; }
+
+ /// <summary>
+ /// Gets or sets the URL.
+ /// </summary>
+ /// <value>The URL.</value>
+ public string Url { get; set; }
+
+ /// <summary>
+ /// Gets or sets the status.
+ /// </summary>
+ /// <value>The status.</value>
+ public LiveTvTunerStatus Status { get; set; }
+
+ /// <summary>
+ /// Gets or sets the channel identifier.
+ /// </summary>
+ /// <value>The channel identifier.</value>
+ public string ChannelId { get; set; }
+
+ /// <summary>
+ /// Gets or sets the recording identifier.
+ /// </summary>
+ /// <value>The recording identifier.</value>
+ public string RecordingId { get; set; }
+
+ /// <summary>
+ /// Gets or sets the name of the program.
+ /// </summary>
+ /// <value>The name of the program.</value>
+ public string ProgramName { get; set; }
+
+ /// <summary>
+ /// Gets or sets the clients.
+ /// </summary>
+ /// <value>The clients.</value>
+ public List<string> Clients { get; set; }
+
+ /// <summary>
+ /// Gets or sets a value indicating whether this instance can reset.
+ /// </summary>
+ /// <value><c>true</c> if this instance can reset; otherwise, <c>false</c>.</value>
+ public bool CanReset { get; set; }
+
+ public LiveTvTunerInfo()
+ {
+ Clients = new List<string>();
+ }
+ }
+} \ No newline at end of file
diff --git a/MediaBrowser.Controller/LiveTv/ProgramInfo.cs b/MediaBrowser.Controller/LiveTv/ProgramInfo.cs
new file mode 100644
index 000000000..9e3cbdded
--- /dev/null
+++ b/MediaBrowser.Controller/LiveTv/ProgramInfo.cs
@@ -0,0 +1,213 @@
+using MediaBrowser.Model.LiveTv;
+using System;
+using System.Collections.Generic;
+using MediaBrowser.Model.Entities;
+
+namespace MediaBrowser.Controller.LiveTv
+{
+ public class ProgramInfo
+ {
+ /// <summary>
+ /// Id of the program.
+ /// </summary>
+ public string Id { get; set; }
+
+ /// <summary>
+ /// Gets or sets the channel identifier.
+ /// </summary>
+ /// <value>The channel identifier.</value>
+ public string ChannelId { get; set; }
+
+ /// <summary>
+ /// Name of the program
+ /// </summary>
+ public string Name { get; set; }
+
+ /// <summary>
+ /// Gets or sets the official rating.
+ /// </summary>
+ /// <value>The official rating.</value>
+ public string OfficialRating { get; set; }
+
+ /// <summary>
+ /// Gets or sets the overview.
+ /// </summary>
+ /// <value>The overview.</value>
+ public string Overview { get; set; }
+ /// <summary>
+ /// Gets or sets the short overview.
+ /// </summary>
+ /// <value>The short overview.</value>
+ public string ShortOverview { get; set; }
+
+ /// <summary>
+ /// The start date of the program, in UTC.
+ /// </summary>
+ public DateTime StartDate { get; set; }
+
+ /// <summary>
+ /// The end date of the program, in UTC.
+ /// </summary>
+ public DateTime EndDate { get; set; }
+
+ /// <summary>
+ /// Genre of the program.
+ /// </summary>
+ public List<string> Genres { get; set; }
+
+ /// <summary>
+ /// Gets or sets the original air date.
+ /// </summary>
+ /// <value>The original air date.</value>
+ public DateTime? OriginalAirDate { get; set; }
+
+ /// <summary>
+ /// Gets or sets a value indicating whether this instance is hd.
+ /// </summary>
+ /// <value><c>true</c> if this instance is hd; otherwise, <c>false</c>.</value>
+ public bool? IsHD { get; set; }
+
+ public bool? Is3D { get; set; }
+
+ /// <summary>
+ /// Gets or sets the audio.
+ /// </summary>
+ /// <value>The audio.</value>
+ public ProgramAudio? Audio { get; set; }
+
+ /// <summary>
+ /// Gets or sets the community rating.
+ /// </summary>
+ /// <value>The community rating.</value>
+ public float? CommunityRating { get; set; }
+
+ /// <summary>
+ /// Gets or sets a value indicating whether this instance is repeat.
+ /// </summary>
+ /// <value><c>true</c> if this instance is repeat; otherwise, <c>false</c>.</value>
+ public bool IsRepeat { get; set; }
+
+ public bool IsSubjectToBlackout { get; set; }
+
+ /// <summary>
+ /// Gets or sets the episode title.
+ /// </summary>
+ /// <value>The episode title.</value>
+ public string EpisodeTitle { get; set; }
+
+ /// <summary>
+ /// Supply the image path if it can be accessed directly from the file system
+ /// </summary>
+ /// <value>The image path.</value>
+ public string ImagePath { get; set; }
+
+ /// <summary>
+ /// Supply the image url if it can be downloaded
+ /// </summary>
+ /// <value>The image URL.</value>
+ public string ImageUrl { get; set; }
+
+ public string ThumbImageUrl { get; set; }
+
+ public string LogoImageUrl { get; set; }
+
+ public string BackdropImageUrl { get; set; }
+
+ /// <summary>
+ /// Gets or sets a value indicating whether this instance has image.
+ /// </summary>
+ /// <value><c>null</c> if [has image] contains no value, <c>true</c> if [has image]; otherwise, <c>false</c>.</value>
+ public bool? HasImage { get; set; }
+
+ /// <summary>
+ /// Gets or sets a value indicating whether this instance is movie.
+ /// </summary>
+ /// <value><c>true</c> if this instance is movie; otherwise, <c>false</c>.</value>
+ public bool IsMovie { get; set; }
+
+ /// <summary>
+ /// Gets or sets a value indicating whether this instance is sports.
+ /// </summary>
+ /// <value><c>true</c> if this instance is sports; otherwise, <c>false</c>.</value>
+ public bool IsSports { get; set; }
+
+ /// <summary>
+ /// Gets or sets a value indicating whether this instance is series.
+ /// </summary>
+ /// <value><c>true</c> if this instance is series; otherwise, <c>false</c>.</value>
+ public bool IsSeries { get; set; }
+
+ /// <summary>
+ /// Gets or sets a value indicating whether this instance is live.
+ /// </summary>
+ /// <value><c>true</c> if this instance is live; otherwise, <c>false</c>.</value>
+ public bool IsLive { get; set; }
+
+ /// <summary>
+ /// Gets or sets a value indicating whether this instance is news.
+ /// </summary>
+ /// <value><c>true</c> if this instance is news; otherwise, <c>false</c>.</value>
+ public bool IsNews { get; set; }
+
+ /// <summary>
+ /// Gets or sets a value indicating whether this instance is kids.
+ /// </summary>
+ /// <value><c>true</c> if this instance is kids; otherwise, <c>false</c>.</value>
+ public bool IsKids { get; set; }
+
+ public bool IsEducational { get; set; }
+
+ /// <summary>
+ /// Gets or sets a value indicating whether this instance is premiere.
+ /// </summary>
+ /// <value><c>true</c> if this instance is premiere; otherwise, <c>false</c>.</value>
+ public bool IsPremiere { get; set; }
+
+ /// <summary>
+ /// Gets or sets the production year.
+ /// </summary>
+ /// <value>The production year.</value>
+ public int? ProductionYear { get; set; }
+ /// <summary>
+ /// Gets or sets the home page URL.
+ /// </summary>
+ /// <value>The home page URL.</value>
+ public string HomePageUrl { get; set; }
+ /// <summary>
+ /// Gets or sets the series identifier.
+ /// </summary>
+ /// <value>The series identifier.</value>
+ public string SeriesId { get; set; }
+ /// <summary>
+ /// Gets or sets the show identifier.
+ /// </summary>
+ /// <value>The show identifier.</value>
+ public string ShowId { get; set; }
+ /// <summary>
+ /// Gets or sets the season number.
+ /// </summary>
+ /// <value>The season number.</value>
+ public int? SeasonNumber { get; set; }
+ /// <summary>
+ /// Gets or sets the episode number.
+ /// </summary>
+ /// <value>The episode number.</value>
+ public int? EpisodeNumber { get; set; }
+ /// <summary>
+ /// Gets or sets the etag.
+ /// </summary>
+ /// <value>The etag.</value>
+ public string Etag { get; set; }
+
+ public Dictionary<string, string> ProviderIds { get; set; }
+ public Dictionary<string, string> SeriesProviderIds { get; set; }
+
+ public ProgramInfo()
+ {
+ Genres = new List<string>();
+
+ ProviderIds = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);
+ SeriesProviderIds = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);
+ }
+ }
+}
diff --git a/MediaBrowser.Controller/LiveTv/RecordingInfo.cs b/MediaBrowser.Controller/LiveTv/RecordingInfo.cs
new file mode 100644
index 000000000..3006b9bbe
--- /dev/null
+++ b/MediaBrowser.Controller/LiveTv/RecordingInfo.cs
@@ -0,0 +1,205 @@
+using MediaBrowser.Model.LiveTv;
+using System;
+using System.Collections.Generic;
+
+namespace MediaBrowser.Controller.LiveTv
+{
+ public class RecordingInfo
+ {
+ /// <summary>
+ /// Id of the recording.
+ /// </summary>
+ public string Id { get; set; }
+
+ /// <summary>
+ /// Gets or sets the series timer identifier.
+ /// </summary>
+ /// <value>The series timer identifier.</value>
+ public string SeriesTimerId { get; set; }
+
+ /// <summary>
+ /// Gets or sets the timer identifier.
+ /// </summary>
+ /// <value>The timer identifier.</value>
+ public string TimerId { get; set; }
+
+ /// <summary>
+ /// ChannelId of the recording.
+ /// </summary>
+ public string ChannelId { get; set; }
+
+ /// <summary>
+ /// Gets or sets the type of the channel.
+ /// </summary>
+ /// <value>The type of the channel.</value>
+ public ChannelType ChannelType { get; set; }
+
+ /// <summary>
+ /// Name of the recording.
+ /// </summary>
+ public string Name { get; set; }
+
+ /// <summary>
+ /// Gets or sets the path.
+ /// </summary>
+ /// <value>The path.</value>
+ public string Path { get; set; }
+
+ /// <summary>
+ /// Gets or sets the URL.
+ /// </summary>
+ /// <value>The URL.</value>
+ public string Url { get; set; }
+
+ /// <summary>
+ /// Gets or sets the overview.
+ /// </summary>
+ /// <value>The overview.</value>
+ public string Overview { get; set; }
+
+ /// <summary>
+ /// The start date of the recording, in UTC.
+ /// </summary>
+ public DateTime StartDate { get; set; }
+
+ /// <summary>
+ /// The end date of the recording, in UTC.
+ /// </summary>
+ public DateTime EndDate { get; set; }
+
+ /// <summary>
+ /// Gets or sets the program identifier.
+ /// </summary>
+ /// <value>The program identifier.</value>
+ public string ProgramId { get; set; }
+
+ /// <summary>
+ /// Gets or sets the status.
+ /// </summary>
+ /// <value>The status.</value>
+ public RecordingStatus Status { get; set; }
+
+ /// <summary>
+ /// Genre of the program.
+ /// </summary>
+ public List<string> Genres { get; set; }
+
+ /// <summary>
+ /// Gets or sets a value indicating whether this instance is repeat.
+ /// </summary>
+ /// <value><c>true</c> if this instance is repeat; otherwise, <c>false</c>.</value>
+ public bool IsRepeat { get; set; }
+
+ /// <summary>
+ /// Gets or sets the episode title.
+ /// </summary>
+ /// <value>The episode title.</value>
+ public string EpisodeTitle { get; set; }
+
+ /// <summary>
+ /// Gets or sets a value indicating whether this instance is hd.
+ /// </summary>
+ /// <value><c>true</c> if this instance is hd; otherwise, <c>false</c>.</value>
+ public bool? IsHD { get; set; }
+
+ /// <summary>
+ /// Gets or sets the audio.
+ /// </summary>
+ /// <value>The audio.</value>
+ public ProgramAudio? Audio { get; set; }
+
+ /// <summary>
+ /// Gets or sets the original air date.
+ /// </summary>
+ /// <value>The original air date.</value>
+ public DateTime? OriginalAirDate { get; set; }
+
+ /// <summary>
+ /// Gets or sets a value indicating whether this instance is movie.
+ /// </summary>
+ /// <value><c>true</c> if this instance is movie; otherwise, <c>false</c>.</value>
+ public bool IsMovie { get; set; }
+
+ /// <summary>
+ /// Gets or sets a value indicating whether this instance is sports.
+ /// </summary>
+ /// <value><c>true</c> if this instance is sports; otherwise, <c>false</c>.</value>
+ public bool IsSports { get; set; }
+
+ /// <summary>
+ /// Gets or sets a value indicating whether this instance is series.
+ /// </summary>
+ /// <value><c>true</c> if this instance is series; otherwise, <c>false</c>.</value>
+ public bool IsSeries { get; set; }
+
+ /// <summary>
+ /// Gets or sets a value indicating whether this instance is live.
+ /// </summary>
+ /// <value><c>true</c> if this instance is live; otherwise, <c>false</c>.</value>
+ public bool IsLive { get; set; }
+
+ /// <summary>
+ /// Gets or sets a value indicating whether this instance is news.
+ /// </summary>
+ /// <value><c>true</c> if this instance is news; otherwise, <c>false</c>.</value>
+ public bool IsNews { get; set; }
+
+ /// <summary>
+ /// Gets or sets a value indicating whether this instance is kids.
+ /// </summary>
+ /// <value><c>true</c> if this instance is kids; otherwise, <c>false</c>.</value>
+ public bool IsKids { get; set; }
+
+ /// <summary>
+ /// Gets or sets a value indicating whether this instance is premiere.
+ /// </summary>
+ /// <value><c>true</c> if this instance is premiere; otherwise, <c>false</c>.</value>
+ public bool IsPremiere { get; set; }
+
+ /// <summary>
+ /// Gets or sets the official rating.
+ /// </summary>
+ /// <value>The official rating.</value>
+ public string OfficialRating { get; set; }
+
+ /// <summary>
+ /// Gets or sets the community rating.
+ /// </summary>
+ /// <value>The community rating.</value>
+ public float? CommunityRating { get; set; }
+
+ /// <summary>
+ /// Supply the image path if it can be accessed directly from the file system
+ /// </summary>
+ /// <value>The image path.</value>
+ public string ImagePath { get; set; }
+
+ /// <summary>
+ /// Supply the image url if it can be downloaded
+ /// </summary>
+ /// <value>The image URL.</value>
+ public string ImageUrl { get; set; }
+
+ /// <summary>
+ /// Gets or sets a value indicating whether this instance has image.
+ /// </summary>
+ /// <value><c>null</c> if [has image] contains no value, <c>true</c> if [has image]; otherwise, <c>false</c>.</value>
+ public bool? HasImage { get; set; }
+ /// <summary>
+ /// Gets or sets the show identifier.
+ /// </summary>
+ /// <value>The show identifier.</value>
+ public string ShowId { get; set; }
+
+ /// <summary>
+ /// Gets or sets the date last updated.
+ /// </summary>
+ /// <value>The date last updated.</value>
+ public DateTime DateLastUpdated { get; set; }
+
+ public RecordingInfo()
+ {
+ Genres = new List<string>();
+ }
+ }
+}
diff --git a/MediaBrowser.Controller/LiveTv/RecordingStatusChangedEventArgs.cs b/MediaBrowser.Controller/LiveTv/RecordingStatusChangedEventArgs.cs
new file mode 100644
index 000000000..90ea329fe
--- /dev/null
+++ b/MediaBrowser.Controller/LiveTv/RecordingStatusChangedEventArgs.cs
@@ -0,0 +1,12 @@
+using MediaBrowser.Model.LiveTv;
+using System;
+
+namespace MediaBrowser.Controller.LiveTv
+{
+ public class RecordingStatusChangedEventArgs : EventArgs
+ {
+ public string RecordingId { get; set; }
+
+ public RecordingStatus NewStatus { get; set; }
+ }
+}
diff --git a/MediaBrowser.Controller/LiveTv/SeriesTimerInfo.cs b/MediaBrowser.Controller/LiveTv/SeriesTimerInfo.cs
new file mode 100644
index 000000000..5c73ed833
--- /dev/null
+++ b/MediaBrowser.Controller/LiveTv/SeriesTimerInfo.cs
@@ -0,0 +1,119 @@
+using System;
+using System.Collections.Generic;
+using MediaBrowser.Model.LiveTv;
+
+namespace MediaBrowser.Controller.LiveTv
+{
+ public class SeriesTimerInfo
+ {
+ /// <summary>
+ /// Id of the recording.
+ /// </summary>
+ public string Id { get; set; }
+
+ /// <summary>
+ /// ChannelId of the recording.
+ /// </summary>
+ public string ChannelId { get; set; }
+
+ /// <summary>
+ /// Gets or sets the program identifier.
+ /// </summary>
+ /// <value>The program identifier.</value>
+ public string ProgramId { get; set; }
+
+ /// <summary>
+ /// Name of the recording.
+ /// </summary>
+ public string Name { get; set; }
+
+ public string ServiceName { get; set; }
+
+ /// <summary>
+ /// Description of the recording.
+ /// </summary>
+ public string Overview { get; set; }
+
+ /// <summary>
+ /// The start date of the recording, in UTC.
+ /// </summary>
+ public DateTime StartDate { get; set; }
+
+ /// <summary>
+ /// The end date of the recording, in UTC.
+ /// </summary>
+ public DateTime EndDate { get; set; }
+
+ /// <summary>
+ /// Gets or sets a value indicating whether [record any time].
+ /// </summary>
+ /// <value><c>true</c> if [record any time]; otherwise, <c>false</c>.</value>
+ public bool RecordAnyTime { get; set; }
+
+ /// <summary>
+ /// Gets or sets a value indicating whether [record any channel].
+ /// </summary>
+ /// <value><c>true</c> if [record any channel]; otherwise, <c>false</c>.</value>
+ public bool RecordAnyChannel { get; set; }
+
+ public int KeepUpTo { get; set; }
+ public KeepUntil KeepUntil { get; set; }
+
+ public bool SkipEpisodesInLibrary { get; set; }
+
+ /// <summary>
+ /// Gets or sets a value indicating whether [record new only].
+ /// </summary>
+ /// <value><c>true</c> if [record new only]; otherwise, <c>false</c>.</value>
+ public bool RecordNewOnly { get; set; }
+
+ /// <summary>
+ /// Gets or sets the days.
+ /// </summary>
+ /// <value>The days.</value>
+ public List<DayOfWeek> Days { get; set; }
+
+ /// <summary>
+ /// Gets or sets the priority.
+ /// </summary>
+ /// <value>The priority.</value>
+ public int Priority { get; set; }
+
+ /// <summary>
+ /// Gets or sets the pre padding seconds.
+ /// </summary>
+ /// <value>The pre padding seconds.</value>
+ public int PrePaddingSeconds { get; set; }
+
+ /// <summary>
+ /// Gets or sets the post padding seconds.
+ /// </summary>
+ /// <value>The post padding seconds.</value>
+ public int PostPaddingSeconds { get; set; }
+
+ /// <summary>
+ /// Gets or sets a value indicating whether this instance is pre padding required.
+ /// </summary>
+ /// <value><c>true</c> if this instance is pre padding required; otherwise, <c>false</c>.</value>
+ public bool IsPrePaddingRequired { get; set; }
+
+ /// <summary>
+ /// Gets or sets a value indicating whether this instance is post padding required.
+ /// </summary>
+ /// <value><c>true</c> if this instance is post padding required; otherwise, <c>false</c>.</value>
+ public bool IsPostPaddingRequired { get; set; }
+
+ /// <summary>
+ /// Gets or sets the series identifier.
+ /// </summary>
+ /// <value>The series identifier.</value>
+ public string SeriesId { get; set; }
+
+ public SeriesTimerInfo()
+ {
+ Days = new List<DayOfWeek>();
+ SkipEpisodesInLibrary = true;
+ KeepUntil = KeepUntil.UntilDeleted;
+ }
+ }
+}
diff --git a/MediaBrowser.Controller/LiveTv/TimerEventInfo.cs b/MediaBrowser.Controller/LiveTv/TimerEventInfo.cs
new file mode 100644
index 000000000..5b71a26a2
--- /dev/null
+++ b/MediaBrowser.Controller/LiveTv/TimerEventInfo.cs
@@ -0,0 +1,10 @@
+using System;
+
+namespace MediaBrowser.Controller.LiveTv
+{
+ public class TimerEventInfo
+ {
+ public string Id { get; set; }
+ public Guid ProgramId { get; set; }
+ }
+}
diff --git a/MediaBrowser.Controller/LiveTv/TimerInfo.cs b/MediaBrowser.Controller/LiveTv/TimerInfo.cs
new file mode 100644
index 000000000..baf0b0b13
--- /dev/null
+++ b/MediaBrowser.Controller/LiveTv/TimerInfo.cs
@@ -0,0 +1,175 @@
+using MediaBrowser.Model.LiveTv;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using MediaBrowser.Model.Serialization;
+
+namespace MediaBrowser.Controller.LiveTv
+{
+ public class TimerInfo
+ {
+ public TimerInfo()
+ {
+ Genres = new string[] { };
+ KeepUntil = KeepUntil.UntilDeleted;
+ ProviderIds = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);
+ SeriesProviderIds = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);
+ Tags = new string[] { };
+ }
+
+ public Dictionary<string, string> ProviderIds { get; set; }
+ public Dictionary<string, string> SeriesProviderIds { get; set; }
+ public string[] Tags { get; set; }
+
+ /// <summary>
+ /// Id of the recording.
+ /// </summary>
+ public string Id { get; set; }
+
+ /// <summary>
+ /// Gets or sets the series timer identifier.
+ /// </summary>
+ /// <value>The series timer identifier.</value>
+ public string SeriesTimerId { get; set; }
+
+ /// <summary>
+ /// ChannelId of the recording.
+ /// </summary>
+ public string ChannelId { get; set; }
+
+ /// <summary>
+ /// Gets or sets the program identifier.
+ /// </summary>
+ /// <value>The program identifier.</value>
+ public string ProgramId { get; set; }
+
+ public string ShowId { get; set; }
+
+ /// <summary>
+ /// Name of the recording.
+ /// </summary>
+ public string Name { get; set; }
+
+ /// <summary>
+ /// Description of the recording.
+ /// </summary>
+ public string Overview { get; set; }
+
+ public string SeriesId { get; set; }
+
+ /// <summary>
+ /// The start date of the recording, in UTC.
+ /// </summary>
+ public DateTime StartDate { get; set; }
+
+ /// <summary>
+ /// The end date of the recording, in UTC.
+ /// </summary>
+ public DateTime EndDate { get; set; }
+
+ /// <summary>
+ /// Gets or sets the status.
+ /// </summary>
+ /// <value>The status.</value>
+ public RecordingStatus Status { get; set; }
+
+ /// <summary>
+ /// Gets or sets the pre padding seconds.
+ /// </summary>
+ /// <value>The pre padding seconds.</value>
+ public int PrePaddingSeconds { get; set; }
+
+ /// <summary>
+ /// Gets or sets the post padding seconds.
+ /// </summary>
+ /// <value>The post padding seconds.</value>
+ public int PostPaddingSeconds { get; set; }
+
+ /// <summary>
+ /// Gets or sets a value indicating whether this instance is pre padding required.
+ /// </summary>
+ /// <value><c>true</c> if this instance is pre padding required; otherwise, <c>false</c>.</value>
+ public bool IsPrePaddingRequired { get; set; }
+
+ /// <summary>
+ /// Gets or sets a value indicating whether this instance is post padding required.
+ /// </summary>
+ /// <value><c>true</c> if this instance is post padding required; otherwise, <c>false</c>.</value>
+ public bool IsPostPaddingRequired { get; set; }
+
+ public bool IsManual { get; set; }
+
+ /// <summary>
+ /// Gets or sets the priority.
+ /// </summary>
+ /// <value>The priority.</value>
+ public int Priority { get; set; }
+
+ public int RetryCount { get; set; }
+
+ // Program properties
+ public int? SeasonNumber { get; set; }
+ /// <summary>
+ /// Gets or sets the episode number.
+ /// </summary>
+ /// <value>The episode number.</value>
+ public int? EpisodeNumber { get; set; }
+ public bool IsMovie { get; set; }
+ public bool IsKids
+ {
+ get
+ {
+ return Tags.Contains("Kids", StringComparer.OrdinalIgnoreCase);
+ }
+ }
+ public bool IsSports
+ {
+ get
+ {
+ return Tags.Contains("Sports", StringComparer.OrdinalIgnoreCase);
+ }
+ }
+ public bool IsNews
+ {
+ get
+ {
+ return Tags.Contains("News", StringComparer.OrdinalIgnoreCase);
+ }
+ }
+ public bool IsSeries { get; set; }
+
+ /// <summary>
+ /// Gets or sets a value indicating whether this instance is live.
+ /// </summary>
+ /// <value><c>true</c> if this instance is live; otherwise, <c>false</c>.</value>
+ [IgnoreDataMember]
+ public bool IsLive
+ {
+ get
+ {
+ return Tags.Contains("Live", StringComparer.OrdinalIgnoreCase);
+ }
+ }
+
+ [IgnoreDataMember]
+ public bool IsPremiere
+ {
+ get
+ {
+ return Tags.Contains("Premiere", StringComparer.OrdinalIgnoreCase);
+ }
+ }
+
+ public int? ProductionYear { get; set; }
+ public string EpisodeTitle { get; set; }
+ public DateTime? OriginalAirDate { get; set; }
+ public bool IsProgramSeries { get; set; }
+ public bool IsRepeat { get; set; }
+ public string HomePageUrl { get; set; }
+ public float? CommunityRating { get; set; }
+ public string OfficialRating { get; set; }
+ public string[] Genres { get; set; }
+ public string RecordingPath { get; set; }
+ public KeepUntil KeepUntil { get; set; }
+ }
+}
diff --git a/MediaBrowser.Controller/LiveTv/TunerChannelMapping.cs b/MediaBrowser.Controller/LiveTv/TunerChannelMapping.cs
new file mode 100644
index 000000000..3b2df0471
--- /dev/null
+++ b/MediaBrowser.Controller/LiveTv/TunerChannelMapping.cs
@@ -0,0 +1,10 @@
+namespace MediaBrowser.Controller.LiveTv
+{
+ public class TunerChannelMapping
+ {
+ public string Name { get; set; }
+ public string ProviderChannelName { get; set; }
+ public string ProviderChannelId { get; set; }
+ public string Id { get; set; }
+ }
+}