diff --git a/MediaBrowser.Api/ApiEntryPoint.cs b/MediaBrowser.Api/ApiEntryPoint.cs
index 2f5b9e1e0..c6e45c61a 100644
--- a/MediaBrowser.Api/ApiEntryPoint.cs
+++ b/MediaBrowser.Api/ApiEntryPoint.cs
@@ -567,7 +567,7 @@ namespace MediaBrowser.Api
{
try
{
- await _mediaSourceManager.CloseLiveStream(job.LiveStreamId, CancellationToken.None).ConfigureAwait(false);
+ await _mediaSourceManager.CloseLiveStream(job.LiveStreamId).ConfigureAwait(false);
}
catch (Exception ex)
{
@@ -789,12 +789,12 @@ namespace MediaBrowser.Api
{
if (KillTimer == null)
{
- Logger.Debug("Starting kill timer at {0}ms. JobId {1} PlaySessionId {2}", intervalMs, Id, PlaySessionId);
+ //Logger.Debug("Starting kill timer at {0}ms. JobId {1} PlaySessionId {2}", intervalMs, Id, PlaySessionId);
KillTimer = new Timer(callback, this, intervalMs, Timeout.Infinite);
}
else
{
- Logger.Debug("Changing kill timer to {0}ms. JobId {1} PlaySessionId {2}", intervalMs, Id, PlaySessionId);
+ //Logger.Debug("Changing kill timer to {0}ms. JobId {1} PlaySessionId {2}", intervalMs, Id, PlaySessionId);
KillTimer.Change(intervalMs, Timeout.Infinite);
}
}
@@ -813,7 +813,7 @@ namespace MediaBrowser.Api
{
var intervalMs = PingTimeout;
- Logger.Debug("Changing kill timer to {0}ms. JobId {1} PlaySessionId {2}", intervalMs, Id, PlaySessionId);
+ //Logger.Debug("Changing kill timer to {0}ms. JobId {1} PlaySessionId {2}", intervalMs, Id, PlaySessionId);
KillTimer.Change(intervalMs, Timeout.Infinite);
}
}
diff --git a/MediaBrowser.Api/LiveTv/LiveTvService.cs b/MediaBrowser.Api/LiveTv/LiveTvService.cs
index a5f8fce6e..9c1105082 100644
--- a/MediaBrowser.Api/LiveTv/LiveTvService.cs
+++ b/MediaBrowser.Api/LiveTv/LiveTvService.cs
@@ -48,6 +48,21 @@ namespace MediaBrowser.Api.LiveTv
[ApiMember(Name = "StartIndex", Description = "Optional. The record index to start at. All items with a lower index will be dropped from the results.", IsRequired = false, DataType = "int", ParameterType = "query", Verb = "GET")]
public int? StartIndex { get; set; }
+ [ApiMember(Name = "IsMovie", Description = "Optional filter for movies.", IsRequired = false, DataType = "bool", ParameterType = "query", Verb = "GET,POST")]
+ public bool? IsMovie { get; set; }
+
+ [ApiMember(Name = "IsSeries", Description = "Optional filter for movies.", IsRequired = false, DataType = "bool", ParameterType = "query", Verb = "GET,POST")]
+ public bool? IsSeries { get; set; }
+
+ [ApiMember(Name = "IsNews", Description = "Optional filter for news.", IsRequired = false, DataType = "bool", ParameterType = "query", Verb = "GET,POST")]
+ public bool? IsNews { get; set; }
+
+ [ApiMember(Name = "IsKids", Description = "Optional filter for kids.", IsRequired = false, DataType = "bool", ParameterType = "query", Verb = "GET,POST")]
+ public bool? IsKids { get; set; }
+
+ [ApiMember(Name = "IsSports", Description = "Optional filter for sports.", IsRequired = false, DataType = "bool", ParameterType = "query", Verb = "GET,POST")]
+ public bool? IsSports { get; set; }
+
///
/// The maximum number of items to return
///
@@ -163,6 +178,7 @@ namespace MediaBrowser.Api.LiveTv
public bool? IsSeries { get; set; }
public bool? IsKids { get; set; }
public bool? IsSports { get; set; }
+ public bool? IsNews { get; set; }
public GetRecordings()
{
@@ -309,6 +325,12 @@ namespace MediaBrowser.Api.LiveTv
[ApiMember(Name = "IsMovie", Description = "Optional filter for movies.", IsRequired = false, DataType = "bool", ParameterType = "query", Verb = "GET,POST")]
public bool? IsMovie { get; set; }
+ [ApiMember(Name = "IsSeries", Description = "Optional filter for movies.", IsRequired = false, DataType = "bool", ParameterType = "query", Verb = "GET,POST")]
+ public bool? IsSeries { get; set; }
+
+ [ApiMember(Name = "IsNews", Description = "Optional filter for news.", IsRequired = false, DataType = "bool", ParameterType = "query", Verb = "GET,POST")]
+ public bool? IsNews { get; set; }
+
[ApiMember(Name = "IsKids", Description = "Optional filter for kids.", IsRequired = false, DataType = "bool", ParameterType = "query", Verb = "GET,POST")]
public bool? IsKids { get; set; }
@@ -380,15 +402,21 @@ namespace MediaBrowser.Api.LiveTv
[ApiMember(Name = "HasAired", Description = "Optional. Filter by programs that have completed airing, or not.", IsRequired = false, DataType = "bool", ParameterType = "query", Verb = "GET")]
public bool? HasAired { get; set; }
- [ApiMember(Name = "IsSports", Description = "Optional filter for sports.", IsRequired = false, DataType = "bool", ParameterType = "query", Verb = "GET,POST")]
- public bool? IsSports { get; set; }
+ [ApiMember(Name = "IsSeries", Description = "Optional filter for movies.", IsRequired = false, DataType = "bool", ParameterType = "query", Verb = "GET,POST")]
+ public bool? IsSeries { get; set; }
- [ApiMember(Name = "IsMovie", Description = "Optional filter for movies.", IsRequired = false, DataType = "bool", ParameterType = "query", Verb = "GET")]
+ [ApiMember(Name = "IsMovie", Description = "Optional filter for movies.", IsRequired = false, DataType = "bool", ParameterType = "query", Verb = "GET,POST")]
public bool? IsMovie { get; set; }
- [ApiMember(Name = "IsKids", Description = "Optional filter for kids.", IsRequired = false, DataType = "bool", ParameterType = "query", Verb = "GET")]
+ [ApiMember(Name = "IsNews", Description = "Optional filter for news.", IsRequired = false, DataType = "bool", ParameterType = "query", Verb = "GET,POST")]
+ public bool? IsNews { get; set; }
+
+ [ApiMember(Name = "IsKids", Description = "Optional filter for kids.", IsRequired = false, DataType = "bool", ParameterType = "query", Verb = "GET,POST")]
public bool? IsKids { get; set; }
+ [ApiMember(Name = "IsSports", Description = "Optional filter for sports.", IsRequired = false, DataType = "bool", ParameterType = "query", Verb = "GET,POST")]
+ public bool? IsSports { get; set; }
+
[ApiMember(Name = "EnableImages", Description = "Optional, include image information in output", IsRequired = false, DataType = "boolean", ParameterType = "query", Verb = "GET")]
public bool? EnableImages { get; set; }
@@ -815,6 +843,11 @@ namespace MediaBrowser.Api.LiveTv
IsLiked = request.IsLiked,
IsDisliked = request.IsDisliked,
EnableFavoriteSorting = request.EnableFavoriteSorting,
+ IsMovie = request.IsMovie,
+ IsSeries = request.IsSeries,
+ IsNews = request.IsNews,
+ IsKids = request.IsKids,
+ IsSports = request.IsSports,
AddCurrentProgram = request.AddCurrentProgram
}, CancellationToken.None).ConfigureAwait(false);
@@ -897,7 +930,9 @@ namespace MediaBrowser.Api.LiveTv
query.Limit = request.Limit;
query.SortBy = (request.SortBy ?? String.Empty).Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries);
query.SortOrder = request.SortOrder;
+ query.IsNews = request.IsNews;
query.IsMovie = request.IsMovie;
+ query.IsSeries = request.IsSeries;
query.IsKids = request.IsKids;
query.IsSports = request.IsSports;
query.Genres = (request.Genres ?? String.Empty).Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries);
@@ -915,8 +950,10 @@ namespace MediaBrowser.Api.LiveTv
IsAiring = request.IsAiring,
Limit = request.Limit,
HasAired = request.HasAired,
+ IsSeries = request.IsSeries,
IsMovie = request.IsMovie,
IsKids = request.IsKids,
+ IsNews = request.IsNews,
IsSports = request.IsSports,
EnableTotalRecordCount = request.EnableTotalRecordCount
};
@@ -948,6 +985,7 @@ namespace MediaBrowser.Api.LiveTv
IsInProgress = request.IsInProgress,
EnableTotalRecordCount = request.EnableTotalRecordCount,
IsMovie = request.IsMovie,
+ IsNews = request.IsNews,
IsSeries = request.IsSeries,
IsKids = request.IsKids,
IsSports = request.IsSports
diff --git a/MediaBrowser.Api/Playback/BaseStreamingService.cs b/MediaBrowser.Api/Playback/BaseStreamingService.cs
index fe9869664..8e57650b4 100644
--- a/MediaBrowser.Api/Playback/BaseStreamingService.cs
+++ b/MediaBrowser.Api/Playback/BaseStreamingService.cs
@@ -1861,14 +1861,14 @@ namespace MediaBrowser.Api.Playback
MediaSourceInfo mediaSource = null;
if (string.IsNullOrWhiteSpace(request.LiveStreamId))
{
- //TranscodingJob currentJob = !string.IsNullOrWhiteSpace(request.PlaySessionId) ?
- // ApiEntryPoint.Instance.GetTranscodingJob(request.PlaySessionId)
- // : null;
+ TranscodingJob currentJob = !string.IsNullOrWhiteSpace(request.PlaySessionId) ?
+ ApiEntryPoint.Instance.GetTranscodingJob(request.PlaySessionId)
+ : null;
- //if (currentJob != null)
- //{
- // mediaSource = currentJob.MediaSource;
- //}
+ if (currentJob != null)
+ {
+ mediaSource = currentJob.MediaSource;
+ }
if (mediaSource == null)
{
diff --git a/MediaBrowser.Api/Playback/MediaInfoService.cs b/MediaBrowser.Api/Playback/MediaInfoService.cs
index 656b2ee08..761538c83 100644
--- a/MediaBrowser.Api/Playback/MediaInfoService.cs
+++ b/MediaBrowser.Api/Playback/MediaInfoService.cs
@@ -140,7 +140,7 @@ namespace MediaBrowser.Api.Playback
public void Post(CloseMediaSource request)
{
- var task = _mediaSourceManager.CloseLiveStream(request.LiveStreamId, CancellationToken.None);
+ var task = _mediaSourceManager.CloseLiveStream(request.LiveStreamId);
Task.WaitAll(task);
}
diff --git a/MediaBrowser.Api/Playback/Progressive/BaseProgressiveStreamingService.cs b/MediaBrowser.Api/Playback/Progressive/BaseProgressiveStreamingService.cs
index a68319109..4bb62f47f 100644
--- a/MediaBrowser.Api/Playback/Progressive/BaseProgressiveStreamingService.cs
+++ b/MediaBrowser.Api/Playback/Progressive/BaseProgressiveStreamingService.cs
@@ -27,12 +27,10 @@ namespace MediaBrowser.Api.Playback.Progressive
public abstract class BaseProgressiveStreamingService : BaseStreamingService
{
protected readonly IImageProcessor ImageProcessor;
- protected readonly IHttpClient HttpClient;
protected BaseProgressiveStreamingService(IServerConfigurationManager serverConfig, IUserManager userManager, ILibraryManager libraryManager, IIsoManager isoManager, IMediaEncoder mediaEncoder, IFileSystem fileSystem, IDlnaManager dlnaManager, ISubtitleEncoder subtitleEncoder, IDeviceManager deviceManager, IMediaSourceManager mediaSourceManager, IZipClient zipClient, IJsonSerializer jsonSerializer, IImageProcessor imageProcessor, IHttpClient httpClient) : base(serverConfig, userManager, libraryManager, isoManager, mediaEncoder, fileSystem, dlnaManager, subtitleEncoder, deviceManager, mediaSourceManager, zipClient, jsonSerializer)
{
ImageProcessor = imageProcessor;
- HttpClient = httpClient;
}
///
diff --git a/MediaBrowser.Api/Playback/StreamState.cs b/MediaBrowser.Api/Playback/StreamState.cs
index ef0282abc..019f378c5 100644
--- a/MediaBrowser.Api/Playback/StreamState.cs
+++ b/MediaBrowser.Api/Playback/StreamState.cs
@@ -225,7 +225,7 @@ namespace MediaBrowser.Api.Playback
{
try
{
- await _mediaSourceManager.CloseLiveStream(MediaSource.LiveStreamId, CancellationToken.None).ConfigureAwait(false);
+ await _mediaSourceManager.CloseLiveStream(MediaSource.LiveStreamId).ConfigureAwait(false);
}
catch (Exception ex)
{
diff --git a/MediaBrowser.Controller/Entities/InternalItemsQuery.cs b/MediaBrowser.Controller/Entities/InternalItemsQuery.cs
index deea63112..d917b7d6d 100644
--- a/MediaBrowser.Controller/Entities/InternalItemsQuery.cs
+++ b/MediaBrowser.Controller/Entities/InternalItemsQuery.cs
@@ -101,6 +101,8 @@ namespace MediaBrowser.Controller.Entities
public bool? IsMovie { get; set; }
public bool? IsSports { get; set; }
public bool? IsKids { get; set; }
+ public bool? IsNews { get; set; }
+ public bool? IsSeries { get; set; }
public int? MinPlayers { get; set; }
public int? MaxPlayers { get; set; }
diff --git a/MediaBrowser.Controller/Library/IMediaSourceManager.cs b/MediaBrowser.Controller/Library/IMediaSourceManager.cs
index 1df77cdc9..c06470c5e 100644
--- a/MediaBrowser.Controller/Library/IMediaSourceManager.cs
+++ b/MediaBrowser.Controller/Library/IMediaSourceManager.cs
@@ -92,8 +92,7 @@ namespace MediaBrowser.Controller.Library
/// Closes the media source.
///
/// The live stream identifier.
- /// The cancellation token.
/// Task.
- Task CloseLiveStream(string id, CancellationToken cancellationToken);
+ Task CloseLiveStream(string id);
}
}
diff --git a/MediaBrowser.Controller/Library/IMediaSourceProvider.cs b/MediaBrowser.Controller/Library/IMediaSourceProvider.cs
index 5b033af4a..56366e5a8 100644
--- a/MediaBrowser.Controller/Library/IMediaSourceProvider.cs
+++ b/MediaBrowser.Controller/Library/IMediaSourceProvider.cs
@@ -28,8 +28,7 @@ namespace MediaBrowser.Controller.Library
/// Closes the media source.
///
/// The live stream identifier.
- /// The cancellation token.
/// Task.
- Task CloseMediaSource(string liveStreamId, CancellationToken cancellationToken);
+ Task CloseMediaSource(string liveStreamId);
}
}
diff --git a/MediaBrowser.Controller/LiveTv/ILiveTvManager.cs b/MediaBrowser.Controller/LiveTv/ILiveTvManager.cs
index 41c5dbdbb..d65d1ae30 100644
--- a/MediaBrowser.Controller/LiveTv/ILiveTvManager.cs
+++ b/MediaBrowser.Controller/LiveTv/ILiveTvManager.cs
@@ -220,9 +220,8 @@ namespace MediaBrowser.Controller.LiveTv
/// Closes the live stream.
///
/// The identifier.
- /// The cancellation token.
/// Task.
- Task CloseLiveStream(string id, CancellationToken cancellationToken);
+ Task CloseLiveStream(string id);
///
/// Gets the guide information.
diff --git a/MediaBrowser.Controller/LiveTv/ITunerHost.cs b/MediaBrowser.Controller/LiveTv/ITunerHost.cs
index 3c8b964a2..89d035649 100644
--- a/MediaBrowser.Controller/LiveTv/ITunerHost.cs
+++ b/MediaBrowser.Controller/LiveTv/ITunerHost.cs
@@ -22,9 +22,8 @@ namespace MediaBrowser.Controller.LiveTv
///
/// Gets the channels.
///
- /// The cancellation token.
/// Task<IEnumerable<ChannelInfo>>.
- Task> GetChannels(CancellationToken cancellationToken);
+ Task> GetChannels(bool enableCache, CancellationToken cancellationToken);
///
/// Gets the tuner infos.
///
@@ -46,8 +45,6 @@ namespace MediaBrowser.Controller.LiveTv
/// The cancellation token.
/// Task<List<MediaSourceInfo>>.
Task> GetChannelStreamMediaSources(string channelId, CancellationToken cancellationToken);
-
- string ApplyDuration(string streamPath, TimeSpan duration);
}
public interface IConfigurableTunerHost
{
diff --git a/MediaBrowser.Controller/LiveTv/LiveStream.cs b/MediaBrowser.Controller/LiveTv/LiveStream.cs
index 15d09d857..1bb198632 100644
--- a/MediaBrowser.Controller/LiveTv/LiveStream.cs
+++ b/MediaBrowser.Controller/LiveTv/LiveStream.cs
@@ -1,4 +1,5 @@
-using System.Threading;
+using System;
+using System.Threading;
using System.Threading.Tasks;
using MediaBrowser.Model.Dto;
@@ -7,17 +8,27 @@ namespace MediaBrowser.Controller.LiveTv
public class LiveStream
{
public MediaSourceInfo OriginalMediaSource { get; set; }
- public MediaSourceInfo PublicMediaSource { get; set; }
- public string Id { get; set; }
+ public MediaSourceInfo OpenedMediaSource { get; set; }
+ public DateTime DateOpened { get; set; }
+ public int ConsumerCount { get; set; }
+ public ITunerHost TunerHost { get; set; }
+ public string OriginalStreamId { get; set; }
public LiveStream(MediaSourceInfo mediaSource)
{
OriginalMediaSource = mediaSource;
- PublicMediaSource = mediaSource;
- Id = mediaSource.Id;
+ OpenedMediaSource = mediaSource;
}
- public virtual Task Open(CancellationToken cancellationToken)
+ public async Task Open(CancellationToken cancellationToken)
+ {
+ await OpenInternal(cancellationToken).ConfigureAwait(false);
+ DateOpened = DateTime.UtcNow;
+
+ OpenedMediaSource.DateLiveStreamOpened = DateOpened;
+ }
+
+ protected virtual Task OpenInternal(CancellationToken cancellationToken)
{
return Task.FromResult(true);
}
diff --git a/MediaBrowser.Controller/LiveTv/LiveTvChannel.cs b/MediaBrowser.Controller/LiveTv/LiveTvChannel.cs
index 50aeed27d..69a1c24ea 100644
--- a/MediaBrowser.Controller/LiveTv/LiveTvChannel.cs
+++ b/MediaBrowser.Controller/LiveTv/LiveTvChannel.cs
@@ -9,7 +9,7 @@ using System.Runtime.Serialization;
namespace MediaBrowser.Controller.LiveTv
{
- public class LiveTvChannel : BaseItem, IHasMediaSources
+ public class LiveTvChannel : BaseItem, IHasMediaSources, IHasProgramAttributes
{
public override List GetUserDataKeys()
{
@@ -137,5 +137,56 @@ namespace MediaBrowser.Controller.LiveTv
{
return false;
}
+
+ [IgnoreDataMember]
+ public bool IsMovie { get; set; }
+
+ ///
+ /// Gets or sets a value indicating whether this instance is sports.
+ ///
+ /// true if this instance is sports; otherwise, false.
+ [IgnoreDataMember]
+ public bool IsSports { get; set; }
+
+ ///
+ /// Gets or sets a value indicating whether this instance is series.
+ ///
+ /// true if this instance is series; otherwise, false.
+ [IgnoreDataMember]
+ public bool IsSeries { get; set; }
+
+ ///
+ /// Gets or sets a value indicating whether this instance is live.
+ ///
+ /// true if this instance is live; otherwise, false.
+ [IgnoreDataMember]
+ public bool IsLive { get; set; }
+
+ ///
+ /// Gets or sets a value indicating whether this instance is news.
+ ///
+ /// true if this instance is news; otherwise, false.
+ [IgnoreDataMember]
+ public bool IsNews { get; set; }
+
+ ///
+ /// Gets or sets a value indicating whether this instance is kids.
+ ///
+ /// true if this instance is kids; otherwise, false.
+ [IgnoreDataMember]
+ public bool IsKids { get; set; }
+
+ [IgnoreDataMember]
+ public bool IsPremiere { get; set; }
+
+ [IgnoreDataMember]
+ public bool IsRepeat { get; set; }
+
+ ///
+ /// Gets or sets the episode title.
+ ///
+ /// The episode title.
+ [IgnoreDataMember]
+ public string EpisodeTitle { get; set; }
}
}
diff --git a/MediaBrowser.Controller/LiveTv/TimerInfo.cs b/MediaBrowser.Controller/LiveTv/TimerInfo.cs
index 42c3480ce..978e9e1a8 100644
--- a/MediaBrowser.Controller/LiveTv/TimerInfo.cs
+++ b/MediaBrowser.Controller/LiveTv/TimerInfo.cs
@@ -101,6 +101,7 @@ namespace MediaBrowser.Controller.LiveTv
public bool IsMovie { get; set; }
public bool IsKids { get; set; }
public bool IsSports { get; set; }
+ public bool IsNews { get; set; }
public int? ProductionYear { get; set; }
public string EpisodeTitle { get; set; }
public DateTime? OriginalAirDate { get; set; }
diff --git a/MediaBrowser.MediaEncoding/Encoder/EncodingJob.cs b/MediaBrowser.MediaEncoding/Encoder/EncodingJob.cs
index 490a51128..d3738d903 100644
--- a/MediaBrowser.MediaEncoding/Encoder/EncodingJob.cs
+++ b/MediaBrowser.MediaEncoding/Encoder/EncodingJob.cs
@@ -140,7 +140,7 @@ namespace MediaBrowser.MediaEncoding.Encoder
{
try
{
- await _mediaSourceManager.CloseLiveStream(MediaSource.LiveStreamId, CancellationToken.None).ConfigureAwait(false);
+ await _mediaSourceManager.CloseLiveStream(MediaSource.LiveStreamId).ConfigureAwait(false);
}
catch (Exception ex)
{
diff --git a/MediaBrowser.Model/Dto/MediaSourceInfo.cs b/MediaBrowser.Model/Dto/MediaSourceInfo.cs
index bb07d9cb6..2be69c8e4 100644
--- a/MediaBrowser.Model/Dto/MediaSourceInfo.cs
+++ b/MediaBrowser.Model/Dto/MediaSourceInfo.cs
@@ -1,4 +1,5 @@
-using MediaBrowser.Model.Entities;
+using System;
+using MediaBrowser.Model.Entities;
using MediaBrowser.Model.Extensions;
using MediaBrowser.Model.MediaInfo;
using System.Collections.Generic;
@@ -52,7 +53,9 @@ namespace MediaBrowser.Model.Dto
public string TranscodingUrl { get; set; }
public string TranscodingSubProtocol { get; set; }
public string TranscodingContainer { get; set; }
-
+
+ public DateTime? DateLiveStreamOpened { get; set; }
+
public MediaSourceInfo()
{
Formats = new List();
diff --git a/MediaBrowser.Model/LiveTv/LiveTvChannelQuery.cs b/MediaBrowser.Model/LiveTv/LiveTvChannelQuery.cs
index 0ece1e4a0..f76368a7b 100644
--- a/MediaBrowser.Model/LiveTv/LiveTvChannelQuery.cs
+++ b/MediaBrowser.Model/LiveTv/LiveTvChannelQuery.cs
@@ -61,6 +61,30 @@ namespace MediaBrowser.Model.LiveTv
public bool AddCurrentProgram { get; set; }
public bool EnableUserData { get; set; }
+ ///
+ /// Used to specific whether to return news or not
+ ///
+ /// If set to null, all programs will be returned
+ public bool? IsNews { get; set; }
+
+ ///
+ /// Used to specific whether to return movies or not
+ ///
+ /// If set to null, all programs will be returned
+ public bool? IsMovie { get; set; }
+
+ ///
+ /// Gets or sets a value indicating whether this instance is kids.
+ ///
+ /// null if [is kids] contains no value, true if [is kids]; otherwise, false.
+ public bool? IsKids { get; set; }
+ ///
+ /// Gets or sets a value indicating whether this instance is sports.
+ ///
+ /// null if [is sports] contains no value, true if [is sports]; otherwise, false.
+ public bool? IsSports { get; set; }
+ public bool? IsSeries { get; set; }
+
public LiveTvChannelQuery()
{
EnableUserData = true;
diff --git a/MediaBrowser.Model/LiveTv/ProgramQuery.cs b/MediaBrowser.Model/LiveTv/ProgramQuery.cs
index bf459237a..7886342e7 100644
--- a/MediaBrowser.Model/LiveTv/ProgramQuery.cs
+++ b/MediaBrowser.Model/LiveTv/ProgramQuery.cs
@@ -62,6 +62,12 @@ namespace MediaBrowser.Model.LiveTv
///
public DateTime? MaxEndDate { get; set; }
+ ///
+ /// Used to specific whether to return news or not
+ ///
+ /// If set to null, all programs will be returned
+ public bool? IsNews { get; set; }
+
///
/// Used to specific whether to return movies or not
///
@@ -83,6 +89,7 @@ namespace MediaBrowser.Model.LiveTv
/// Skips over a given number of items within the results. Use for paging.
///
public int? StartIndex { get; set; }
+ public bool? IsSeries { get; set; }
///
/// Gets or sets a value indicating whether this instance has aired.
diff --git a/MediaBrowser.Model/LiveTv/RecommendedProgramQuery.cs b/MediaBrowser.Model/LiveTv/RecommendedProgramQuery.cs
index 0e6d081a1..4bc506bf6 100644
--- a/MediaBrowser.Model/LiveTv/RecommendedProgramQuery.cs
+++ b/MediaBrowser.Model/LiveTv/RecommendedProgramQuery.cs
@@ -45,11 +45,17 @@ namespace MediaBrowser.Model.LiveTv
/// The limit.
public int? Limit { get; set; }
+ ///
+ /// Gets or sets a value indicating whether this instance is movie.
+ ///
+ /// null if [is movie] contains no value, true if [is movie]; otherwise, false.
+ public bool? IsNews { get; set; }
///
/// Gets or sets a value indicating whether this instance is movie.
///
/// null if [is movie] contains no value, true if [is movie]; otherwise, false.
public bool? IsMovie { get; set; }
+ public bool? IsSeries { get; set; }
///
/// Gets or sets a value indicating whether this instance is kids.
///
diff --git a/MediaBrowser.Model/LiveTv/RecordingQuery.cs b/MediaBrowser.Model/LiveTv/RecordingQuery.cs
index 0ba5f1779..265aad335 100644
--- a/MediaBrowser.Model/LiveTv/RecordingQuery.cs
+++ b/MediaBrowser.Model/LiveTv/RecordingQuery.cs
@@ -68,6 +68,7 @@ namespace MediaBrowser.Model.LiveTv
/// The fields.
public ItemFields[] Fields { get; set; }
public bool? EnableImages { get; set; }
+ public bool? IsNews { get; set; }
public bool? IsMovie { get; set; }
public bool? IsSeries { get; set; }
public bool? IsKids { get; set; }
diff --git a/MediaBrowser.Server.Implementations/Channels/ChannelDynamicMediaSourceProvider.cs b/MediaBrowser.Server.Implementations/Channels/ChannelDynamicMediaSourceProvider.cs
index 3239b20b2..6cba1b441 100644
--- a/MediaBrowser.Server.Implementations/Channels/ChannelDynamicMediaSourceProvider.cs
+++ b/MediaBrowser.Server.Implementations/Channels/ChannelDynamicMediaSourceProvider.cs
@@ -35,7 +35,7 @@ namespace MediaBrowser.Server.Implementations.Channels
throw new NotImplementedException();
}
- public Task CloseMediaSource(string liveStreamId, CancellationToken cancellationToken)
+ public Task CloseMediaSource(string liveStreamId)
{
throw new NotImplementedException();
}
diff --git a/MediaBrowser.Server.Implementations/Library/MediaSourceManager.cs b/MediaBrowser.Server.Implementations/Library/MediaSourceManager.cs
index c20245a6e..c7650102f 100644
--- a/MediaBrowser.Server.Implementations/Library/MediaSourceManager.cs
+++ b/MediaBrowser.Server.Implementations/Library/MediaSourceManager.cs
@@ -355,7 +355,7 @@ namespace MediaBrowser.Server.Implementations.Library
.ToList();
}
- private readonly ConcurrentDictionary _openStreams = new ConcurrentDictionary(StringComparer.OrdinalIgnoreCase);
+ private readonly Dictionary _openStreams = new Dictionary(StringComparer.OrdinalIgnoreCase);
private readonly SemaphoreSlim _liveStreamSemaphore = new SemaphoreSlim(1, 1);
public async Task OpenLiveStream(LiveStreamRequest request, bool enableAutoClose, CancellationToken cancellationToken)
@@ -383,7 +383,7 @@ namespace MediaBrowser.Server.Implementations.Library
Id = mediaSource.LiveStreamId,
MediaSource = mediaSource
};
- _openStreams.AddOrUpdate(mediaSource.LiveStreamId, info, (key, i) => info);
+ _openStreams[mediaSource.LiveStreamId] = info;
if (enableAutoClose)
{
@@ -421,7 +421,7 @@ namespace MediaBrowser.Server.Implementations.Library
throw new ArgumentNullException("id");
}
- _logger.Debug("Getting live stream {0}", id);
+ _logger.Debug("Getting already opened live stream {0}", id);
await _liveStreamSemaphore.WaitAsync(cancellationToken).ConfigureAwait(false);
@@ -465,17 +465,16 @@ namespace MediaBrowser.Server.Implementations.Library
}
}
- private async Task CloseLiveStreamWithProvider(IMediaSourceProvider provider, string streamId, CancellationToken cancellationToken)
+ private async Task CloseLiveStreamWithProvider(IMediaSourceProvider provider, string streamId)
{
_logger.Info("Closing live stream {0} with provider {1}", streamId, provider.GetType().Name);
try
{
- await provider.CloseMediaSource(streamId, cancellationToken).ConfigureAwait(false);
+ await provider.CloseMediaSource(streamId).ConfigureAwait(false);
}
catch (NotImplementedException)
{
-
}
catch (Exception ex)
{
@@ -483,37 +482,35 @@ namespace MediaBrowser.Server.Implementations.Library
}
}
- public async Task CloseLiveStream(string id, CancellationToken cancellationToken)
+ public async Task CloseLiveStream(string id)
{
if (string.IsNullOrWhiteSpace(id))
{
throw new ArgumentNullException("id");
}
- await _liveStreamSemaphore.WaitAsync(cancellationToken).ConfigureAwait(false);
+ await _liveStreamSemaphore.WaitAsync().ConfigureAwait(false);
try
{
LiveStreamInfo current;
+
if (_openStreams.TryGetValue(id, out current))
{
+ _openStreams.Remove(id);
+ current.Closed = true;
+
if (current.MediaSource.RequiresClosing)
{
var tuple = GetProvider(id);
- await CloseLiveStreamWithProvider(tuple.Item1, tuple.Item2, cancellationToken).ConfigureAwait(false);
+ await CloseLiveStreamWithProvider(tuple.Item1, tuple.Item2).ConfigureAwait(false);
}
- }
- LiveStreamInfo removed;
- if (_openStreams.TryRemove(id, out removed))
- {
- removed.Closed = true;
- }
-
- if (_openStreams.Count == 0)
- {
- StopCloseTimer();
+ if (_openStreams.Count == 0)
+ {
+ StopCloseTimer();
+ }
}
}
finally
@@ -565,10 +562,20 @@ namespace MediaBrowser.Server.Implementations.Library
private async void CloseTimerCallback(object state)
{
- var infos = _openStreams
- .Values
- .Where(i => i.EnableCloseTimer && DateTime.UtcNow - i.Date > _openStreamMaxAge)
- .ToList();
+ List infos;
+ await _liveStreamSemaphore.WaitAsync().ConfigureAwait(false);
+
+ try
+ {
+ infos = _openStreams
+ .Values
+ .Where(i => i.EnableCloseTimer && DateTime.UtcNow - i.Date > _openStreamMaxAge)
+ .ToList();
+ }
+ finally
+ {
+ _liveStreamSemaphore.Release();
+ }
foreach (var info in infos)
{
@@ -576,7 +583,7 @@ namespace MediaBrowser.Server.Implementations.Library
{
try
{
- await CloseLiveStream(info.Id, CancellationToken.None).ConfigureAwait(false);
+ await CloseLiveStream(info.Id).ConfigureAwait(false);
}
catch (Exception ex)
{
@@ -608,12 +615,10 @@ namespace MediaBrowser.Server.Implementations.Library
{
foreach (var key in _openStreams.Keys.ToList())
{
- var task = CloseLiveStream(key, CancellationToken.None);
+ var task = CloseLiveStream(key);
Task.WaitAll(task);
}
-
- _openStreams.Clear();
}
}
}
diff --git a/MediaBrowser.Server.Implementations/LiveTv/EmbyTV/DirectRecorder.cs b/MediaBrowser.Server.Implementations/LiveTv/EmbyTV/DirectRecorder.cs
index 0d043669a..0f8c15e71 100644
--- a/MediaBrowser.Server.Implementations/LiveTv/EmbyTV/DirectRecorder.cs
+++ b/MediaBrowser.Server.Implementations/LiveTv/EmbyTV/DirectRecorder.cs
@@ -47,19 +47,9 @@ namespace MediaBrowser.Server.Implementations.LiveTv.EmbyTV
_logger.Info("Copying recording stream to file {0}", targetFile);
- if (mediaSource.RunTimeTicks.HasValue)
- {
- // The media source already has a fixed duration
- // But add another stop 1 minute later just in case the recording gets stuck for any reason
- var durationToken = new CancellationTokenSource(duration.Add(TimeSpan.FromMinutes(1)));
- cancellationToken = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken, durationToken.Token).Token;
- }
- else
- {
- // The media source if infinite so we need to handle stopping ourselves
- var durationToken = new CancellationTokenSource(duration);
- cancellationToken = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken, durationToken.Token).Token;
- }
+ // The media source if infinite so we need to handle stopping ourselves
+ var durationToken = new CancellationTokenSource(duration);
+ cancellationToken = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken, durationToken.Token).Token;
await CopyUntilCancelled(response.Content, output, cancellationToken).ConfigureAwait(false);
}
diff --git a/MediaBrowser.Server.Implementations/LiveTv/EmbyTV/EmbyTV.cs b/MediaBrowser.Server.Implementations/LiveTv/EmbyTV/EmbyTV.cs
index f53ec3ee8..ef19dcbc9 100644
--- a/MediaBrowser.Server.Implementations/LiveTv/EmbyTV/EmbyTV.cs
+++ b/MediaBrowser.Server.Implementations/LiveTv/EmbyTV/EmbyTV.cs
@@ -340,22 +340,15 @@ namespace MediaBrowser.Server.Implementations.LiveTv.EmbyTV
_timerProvider.Delete(timer);
}
- private List _channelCache = null;
private async Task> GetChannelsAsync(bool enableCache, CancellationToken cancellationToken)
{
- if (enableCache && _channelCache != null)
- {
-
- return _channelCache.ToList();
- }
-
var list = new List();
foreach (var hostInstance in _liveTvManager.TunerHosts)
{
try
{
- var channels = await hostInstance.GetChannels(cancellationToken).ConfigureAwait(false);
+ var channels = await hostInstance.GetChannels(enableCache, cancellationToken).ConfigureAwait(false);
list.AddRange(channels);
}
@@ -388,7 +381,6 @@ namespace MediaBrowser.Server.Implementations.LiveTv.EmbyTV
}
}
- _channelCache = list.ToList();
return list;
}
@@ -400,7 +392,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv.EmbyTV
{
try
{
- var channels = await hostInstance.GetChannels(cancellationToken).ConfigureAwait(false);
+ var channels = await hostInstance.GetChannels(false, cancellationToken).ConfigureAwait(false);
list.AddRange(channels);
}
@@ -632,6 +624,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv.EmbyTV
existingTimer.Genres = updatedTimer.Genres;
existingTimer.HomePageUrl = updatedTimer.HomePageUrl;
existingTimer.IsKids = updatedTimer.IsKids;
+ existingTimer.IsNews = updatedTimer.IsNews;
existingTimer.IsMovie = updatedTimer.IsMovie;
existingTimer.IsProgramSeries = updatedTimer.IsProgramSeries;
existingTimer.IsSports = updatedTimer.IsSports;
@@ -836,32 +829,67 @@ namespace MediaBrowser.Server.Implementations.LiveTv.EmbyTV
{
var result = await GetChannelStreamInternal(channelId, streamId, cancellationToken).ConfigureAwait(false);
- return result.Item1.PublicMediaSource;
+ return result.Item2;
}
- private async Task> GetChannelStreamInternal(string channelId, string streamId, CancellationToken cancellationToken)
+ private MediaSourceInfo CloneMediaSource(MediaSourceInfo mediaSource, int consumerId)
+ {
+ var json = _jsonSerializer.SerializeToString(mediaSource);
+ mediaSource = _jsonSerializer.DeserializeFromString(json);
+
+ mediaSource.Id = consumerId.ToString(CultureInfo.InvariantCulture) + "_" + mediaSource.Id;
+
+ return mediaSource;
+ }
+
+ private async Task> GetChannelStreamInternal(string channelId, string streamId, CancellationToken cancellationToken)
{
_logger.Info("Streaming Channel " + channelId);
- foreach (var hostInstance in _liveTvManager.TunerHosts)
+ await _liveStreamsSemaphore.WaitAsync(cancellationToken).ConfigureAwait(false);
+
+ var result = _liveStreams.Values.FirstOrDefault(i => string.Equals(i.OriginalStreamId, streamId, StringComparison.OrdinalIgnoreCase));
+
+ if (result != null)
{
- try
- {
- var result = await hostInstance.GetChannelStream(channelId, streamId, cancellationToken).ConfigureAwait(false);
+ //result.ConsumerCount++;
- await _liveStreamsSemaphore.WaitAsync().ConfigureAwait(false);
- _liveStreams[result.Id] = result;
- _liveStreamsSemaphore.Release();
+ //_logger.Info("Live stream {0} consumer count is now {1}", streamId, result.ConsumerCount);
- return new Tuple(result, hostInstance);
- }
- catch (FileNotFoundException)
+ //_liveStreamsSemaphore.Release();
+ //return new Tuple(result, CloneMediaSource(result.OpenedMediaSource, result.ConsumerCount - 1), result.TunerHost);
+ }
+
+ try
+ {
+ foreach (var hostInstance in _liveTvManager.TunerHosts)
{
+ try
+ {
+ result = await hostInstance.GetChannelStream(channelId, streamId, cancellationToken).ConfigureAwait(false);
+
+ _liveStreams[result.OpenedMediaSource.Id] = result;
+
+ result.ConsumerCount++;
+ result.TunerHost = hostInstance;
+ result.OriginalStreamId = streamId;
+
+ _logger.Info("Returning mediasource streamId {0}, mediaSource.Id {1}, mediaSource.LiveStreamId {2}",
+ streamId, result.OpenedMediaSource.Id, result.OpenedMediaSource.LiveStreamId);
+
+ return new Tuple(result, CloneMediaSource(result.OpenedMediaSource, 0), hostInstance);
+ }
+ catch (FileNotFoundException)
+ {
+ }
+ catch (OperationCanceledException)
+ {
+ }
}
- catch (Exception e)
- {
- _logger.ErrorException("Error getting channel stream", e);
- }
+ }
+ finally
+ {
+ _liveStreamsSemaphore.Release();
}
throw new ApplicationException("Tuner not found.");
@@ -896,25 +924,41 @@ namespace MediaBrowser.Server.Implementations.LiveTv.EmbyTV
public async Task CloseLiveStream(string id, CancellationToken cancellationToken)
{
- await _liveStreamsSemaphore.WaitAsync().ConfigureAwait(false);
+ // Ignore the consumer id
+ id = id.Substring(id.IndexOf('_') + 1);
+
+ await _liveStreamsSemaphore.WaitAsync(cancellationToken).ConfigureAwait(false);
try
{
LiveStream stream;
if (_liveStreams.TryGetValue(id, out stream))
{
- _liveStreams.Remove(id);
+ stream.ConsumerCount--;
- try
+ _logger.Info("Live stream {0} consumer count is now {1}", id, stream.ConsumerCount);
+
+ if (stream.ConsumerCount <= 0)
{
+ _liveStreams.Remove(id);
+
+ _logger.Info("Closing live stream {0}", id);
+
await stream.Close().ConfigureAwait(false);
_logger.Info("Live stream {0} closed successfully", id);
}
- catch (Exception ex)
- {
- _logger.ErrorException("Error closing live stream", ex);
- }
}
+ else
+ {
+ _logger.Warn("Live stream not found: {0}, unable to close", id);
+ }
+ }
+ catch (OperationCanceledException)
+ {
+ }
+ catch (Exception ex)
+ {
+ _logger.ErrorException("Error closing live stream", ex);
}
finally
{
@@ -1095,20 +1139,18 @@ namespace MediaBrowser.Server.Implementations.LiveTv.EmbyTV
var recordPath = GetRecordingPath(timer, out seriesPath);
var recordingStatus = RecordingStatus.New;
- LiveStream liveStream = null;
+ string liveStreamId = null;
try
{
var allMediaSources =
await GetChannelStreamMediaSources(timer.ChannelId, CancellationToken.None).ConfigureAwait(false);
- var liveStreamInfo =
- await
- GetChannelStreamInternal(timer.ChannelId, allMediaSources[0].Id, CancellationToken.None)
+ var liveStreamInfo = await GetChannelStreamInternal(timer.ChannelId, allMediaSources[0].Id, CancellationToken.None)
.ConfigureAwait(false);
- liveStream = liveStreamInfo.Item1;
- var mediaStreamInfo = liveStreamInfo.Item1.PublicMediaSource;
- var tunerHost = liveStreamInfo.Item2;
+
+ var mediaStreamInfo = liveStreamInfo.Item2;
+ liveStreamId = mediaStreamInfo.Id;
// HDHR doesn't seem to release the tuner right away after first probing with ffmpeg
//await Task.Delay(3000, cancellationToken).ConfigureAwait(false);
@@ -1140,15 +1182,6 @@ namespace MediaBrowser.Server.Implementations.LiveTv.EmbyTV
EnforceKeepUpTo(timer);
};
- var pathWithDuration = tunerHost.ApplyDuration(mediaStreamInfo.Path, duration);
-
- // If it supports supplying duration via url
- if (!string.Equals(pathWithDuration, mediaStreamInfo.Path, StringComparison.OrdinalIgnoreCase))
- {
- mediaStreamInfo.Path = pathWithDuration;
- mediaStreamInfo.RunTimeTicks = duration.Ticks;
- }
-
await recorder.Record(mediaStreamInfo, recordPath, duration, onStarted, cancellationToken)
.ConfigureAwait(false);
@@ -1166,11 +1199,11 @@ namespace MediaBrowser.Server.Implementations.LiveTv.EmbyTV
recordingStatus = RecordingStatus.Error;
}
- if (liveStream != null)
+ if (!string.IsNullOrWhiteSpace(liveStreamId))
{
try
{
- await CloseLiveStream(liveStream.Id, CancellationToken.None).ConfigureAwait(false);
+ await CloseLiveStream(liveStreamId, CancellationToken.None).ConfigureAwait(false);
}
catch (Exception ex)
{
@@ -1251,7 +1284,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv.EmbyTV
}
}
- private readonly SemaphoreSlim _recordingDeleteSemaphore = new SemaphoreSlim(1,1);
+ private readonly SemaphoreSlim _recordingDeleteSemaphore = new SemaphoreSlim(1, 1);
private async Task DeleteLibraryItemsForTimers(List timers)
{
foreach (var timer in timers)
@@ -1295,7 +1328,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv.EmbyTV
}
catch (FileNotFoundException)
{
-
+
}
}
@@ -1492,6 +1525,10 @@ namespace MediaBrowser.Server.Implementations.LiveTv.EmbyTV
{
AddGenre(timer.Genres, "Kids");
}
+ if (timer.IsNews)
+ {
+ AddGenre(timer.Genres, "News");
+ }
foreach (var genre in timer.Genres)
{
diff --git a/MediaBrowser.Server.Implementations/LiveTv/EmbyTV/EncodedRecorder.cs b/MediaBrowser.Server.Implementations/LiveTv/EmbyTV/EncodedRecorder.cs
index f74a76e3f..ce5f14f4b 100644
--- a/MediaBrowser.Server.Implementations/LiveTv/EmbyTV/EncodedRecorder.cs
+++ b/MediaBrowser.Server.Implementations/LiveTv/EmbyTV/EncodedRecorder.cs
@@ -71,38 +71,12 @@ namespace MediaBrowser.Server.Implementations.LiveTv.EmbyTV
var durationToken = new CancellationTokenSource(duration);
cancellationToken = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken, durationToken.Token).Token;
- await RecordFromFile(mediaSource, mediaSource.Path, targetFile, false, duration, onStarted, cancellationToken).ConfigureAwait(false);
+ await RecordFromFile(mediaSource, mediaSource.Path, targetFile, duration, onStarted, cancellationToken).ConfigureAwait(false);
_logger.Info("Recording completed to file {0}", targetFile);
}
- private async void DeleteTempFile(string path)
- {
- for (var i = 0; i < 10; i++)
- {
- try
- {
- File.Delete(path);
- return;
- }
- catch (FileNotFoundException)
- {
- return;
- }
- catch (DirectoryNotFoundException)
- {
- return;
- }
- catch (Exception ex)
- {
- _logger.ErrorException("Error deleting recording temp file", ex);
- }
-
- await Task.Delay(1000).ConfigureAwait(false);
- }
- }
-
- private Task RecordFromFile(MediaSourceInfo mediaSource, string inputFile, string targetFile, bool deleteInputFileAfterCompletion, TimeSpan duration, Action onStarted, CancellationToken cancellationToken)
+ private Task RecordFromFile(MediaSourceInfo mediaSource, string inputFile, string targetFile, TimeSpan duration, Action onStarted, CancellationToken cancellationToken)
{
_targetPath = targetFile;
_fileSystem.CreateDirectory(Path.GetDirectoryName(targetFile));
@@ -143,7 +117,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv.EmbyTV
var commandLineLogMessageBytes = Encoding.UTF8.GetBytes(_json.SerializeToString(mediaSource) + Environment.NewLine + Environment.NewLine + commandLineLogMessage + Environment.NewLine + Environment.NewLine);
_logFileStream.Write(commandLineLogMessageBytes, 0, commandLineLogMessageBytes.Length);
- process.Exited += (sender, args) => OnFfMpegProcessExited(process, inputFile, deleteInputFileAfterCompletion);
+ process.Exited += (sender, args) => OnFfMpegProcessExited(process, inputFile);
process.Start();
@@ -252,7 +226,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv.EmbyTV
///
/// Processes the exited.
///
- private void OnFfMpegProcessExited(Process process, string inputFile, bool deleteInputFileAfterCompletion)
+ private void OnFfMpegProcessExited(Process process, string inputFile)
{
_hasExited = true;
@@ -278,11 +252,6 @@ namespace MediaBrowser.Server.Implementations.LiveTv.EmbyTV
_logger.Error("FFMpeg recording exited with an error for {0}.", _targetPath);
_taskCompletionSource.TrySetException(new Exception(string.Format("Recording for {0} failed", _targetPath)));
}
-
- if (deleteInputFileAfterCompletion)
- {
- DeleteTempFile(inputFile);
- }
}
private void DisposeLogStream()
diff --git a/MediaBrowser.Server.Implementations/LiveTv/EmbyTV/RecordingHelper.cs b/MediaBrowser.Server.Implementations/LiveTv/EmbyTV/RecordingHelper.cs
index f9c04abc5..bb6935e8e 100644
--- a/MediaBrowser.Server.Implementations/LiveTv/EmbyTV/RecordingHelper.cs
+++ b/MediaBrowser.Server.Implementations/LiveTv/EmbyTV/RecordingHelper.cs
@@ -42,6 +42,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv.EmbyTV
timerInfo.EpisodeNumber = programInfo.EpisodeNumber;
timerInfo.IsMovie = programInfo.IsMovie;
timerInfo.IsKids = programInfo.IsKids;
+ timerInfo.IsNews = programInfo.IsNews;
timerInfo.IsSports = programInfo.IsSports;
timerInfo.ProductionYear = programInfo.ProductionYear;
timerInfo.EpisodeTitle = programInfo.EpisodeTitle;
diff --git a/MediaBrowser.Server.Implementations/LiveTv/LiveTvManager.cs b/MediaBrowser.Server.Implementations/LiveTv/LiveTvManager.cs
index 8a4572813..7c61d2396 100644
--- a/MediaBrowser.Server.Implementations/LiveTv/LiveTvManager.cs
+++ b/MediaBrowser.Server.Implementations/LiveTv/LiveTvManager.cs
@@ -62,9 +62,6 @@ namespace MediaBrowser.Server.Implementations.LiveTv
private readonly List _services = new List();
- private readonly ConcurrentDictionary _openStreams =
- new ConcurrentDictionary();
-
private readonly SemaphoreSlim _refreshRecordingsLock = new SemaphoreSlim(1, 1);
private readonly List _tunerHosts = new List();
@@ -153,6 +150,11 @@ namespace MediaBrowser.Server.Implementations.LiveTv
var channels = _libraryManager.GetItemList(new InternalItemsQuery
{
+ IsMovie = query.IsMovie,
+ IsNews = query.IsNews,
+ IsKids = query.IsKids,
+ IsSports = query.IsSports,
+ IsSeries = query.IsSeries,
IncludeItemTypes = new[] { typeof(LiveTvChannel).Name },
SortBy = new[] { ItemSortBy.SortName },
TopParentIds = new[] { topFolder.Id.ToString("N") }
@@ -407,15 +409,6 @@ namespace MediaBrowser.Server.Implementations.LiveTv
_logger.Info("Live stream info: {0}", _jsonSerializer.SerializeToString(info));
Normalize(info, service, isVideo);
- var data = new LiveStreamData
- {
- Info = info,
- IsChannel = isChannel,
- ItemId = id
- };
-
- _openStreams.AddOrUpdate(info.Id, data, (key, i) => data);
-
return info;
}
catch (Exception ex)
@@ -937,8 +930,10 @@ namespace MediaBrowser.Server.Implementations.LiveTv
MaxStartDate = query.MaxStartDate,
ChannelIds = query.ChannelIds,
IsMovie = query.IsMovie,
+ IsSeries = query.IsSeries,
IsSports = query.IsSports,
IsKids = query.IsKids,
+ IsNews = query.IsNews,
Genres = query.Genres,
StartIndex = query.StartIndex,
Limit = query.Limit,
@@ -985,7 +980,9 @@ namespace MediaBrowser.Server.Implementations.LiveTv
{
IncludeItemTypes = new[] { typeof(LiveTvProgram).Name },
IsAiring = query.IsAiring,
+ IsNews = query.IsNews,
IsMovie = query.IsMovie,
+ IsSeries = query.IsSeries,
IsSports = query.IsSports,
IsKids = query.IsKids,
EnableTotalRecordCount = query.EnableTotalRecordCount,
@@ -1014,7 +1011,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv
var programList = programs.ToList();
- var factorChannelWatchCount = (query.IsAiring ?? false) || (query.IsKids ?? false) || (query.IsSports ?? false) || (query.IsMovie ?? false);
+ var factorChannelWatchCount = (query.IsAiring ?? false) || (query.IsKids ?? false) || (query.IsSports ?? false) || (query.IsMovie ?? false) || (query.IsNews ?? false) || (query.IsSeries ?? false);
programs = programList.OrderBy(i => i.StartDate.Date)
.ThenByDescending(i => GetRecommendationScore(i, user.Id, factorChannelWatchCount))
@@ -1305,6 +1302,12 @@ namespace MediaBrowser.Server.Implementations.LiveTv
var start = DateTime.UtcNow.AddHours(-1);
var end = start.AddDays(guideDays);
+ var isMovie = false;
+ var isSports = false;
+ var isNews = false;
+ var isKids = false;
+ var iSSeries = false;
+
var channelPrograms = await service.GetProgramsAsync(currentChannel.ExternalId, start, end, cancellationToken).ConfigureAwait(false);
foreach (var program in channelPrograms)
@@ -1312,7 +1315,40 @@ namespace MediaBrowser.Server.Implementations.LiveTv
var programItem = await GetProgram(program, currentChannel, currentChannel.ChannelType, service.Name, cancellationToken).ConfigureAwait(false);
programs.Add(programItem.Id);
+
+ if (program.IsMovie)
+ {
+ isMovie = true;
+ }
+
+ if (program.IsSeries)
+ {
+ iSSeries = true;
+ }
+
+ if (program.IsSports)
+ {
+ isSports = true;
+ }
+
+ if (program.IsNews)
+ {
+ isNews = true;
+ }
+
+ if (program.IsKids)
+ {
+ isKids = true;
+ }
}
+
+ currentChannel.IsMovie = isMovie;
+ currentChannel.IsNews = isNews;
+ currentChannel.IsSports = isSports;
+ currentChannel.IsKids = isKids;
+ currentChannel.IsSeries = iSSeries;
+
+ await currentChannel.UpdateToRepository(ItemUpdateType.MetadataImport, cancellationToken).ConfigureAwait(false);
}
catch (OperationCanceledException)
{
@@ -1647,6 +1683,12 @@ namespace MediaBrowser.Server.Implementations.LiveTv
recordings = recordings.Where(i => i.IsMovie == val);
}
+ if (query.IsNews.HasValue)
+ {
+ var val = query.IsNews.Value;
+ recordings = recordings.Where(i => i.IsNews == val);
+ }
+
if (query.IsSeries.HasValue)
{
var val = query.IsSeries.Value;
@@ -2444,9 +2486,9 @@ namespace MediaBrowser.Server.Implementations.LiveTv
internal bool IsChannel;
}
- public async Task CloseLiveStream(string id, CancellationToken cancellationToken)
+ public async Task CloseLiveStream(string id)
{
- await _liveStreamSemaphore.WaitAsync(cancellationToken).ConfigureAwait(false);
+ await _liveStreamSemaphore.WaitAsync().ConfigureAwait(false);
try
{
@@ -2461,12 +2503,9 @@ namespace MediaBrowser.Server.Implementations.LiveTv
id = parts[1];
- LiveStreamData data;
- _openStreams.TryRemove(id, out data);
-
_logger.Info("Closing live stream from {0}, stream Id: {1}", service.Name, id);
- await service.CloseLiveStream(id, cancellationToken).ConfigureAwait(false);
+ await service.CloseLiveStream(id, CancellationToken.None).ConfigureAwait(false);
}
catch (Exception ex)
{
@@ -2500,7 +2539,6 @@ namespace MediaBrowser.Server.Implementations.LiveTv
Dispose(true);
}
- private readonly object _disposeLock = new object();
private bool _isDisposed = false;
///
/// Releases unmanaged and - optionally - managed resources.
@@ -2511,18 +2549,6 @@ namespace MediaBrowser.Server.Implementations.LiveTv
if (dispose)
{
_isDisposed = true;
-
- lock (_disposeLock)
- {
- foreach (var stream in _openStreams.Values.ToList())
- {
- var task = CloseLiveStream(stream.Info.Id, CancellationToken.None);
-
- Task.WaitAll(task);
- }
-
- _openStreams.Clear();
- }
}
}
diff --git a/MediaBrowser.Server.Implementations/LiveTv/LiveTvMediaSourceProvider.cs b/MediaBrowser.Server.Implementations/LiveTv/LiveTvMediaSourceProvider.cs
index cdba1873e..aacc0c22b 100644
--- a/MediaBrowser.Server.Implementations/LiveTv/LiveTvMediaSourceProvider.cs
+++ b/MediaBrowser.Server.Implementations/LiveTv/LiveTvMediaSourceProvider.cs
@@ -204,9 +204,9 @@ namespace MediaBrowser.Server.Implementations.LiveTv
}
}
- public Task CloseMediaSource(string liveStreamId, CancellationToken cancellationToken)
+ public Task CloseMediaSource(string liveStreamId)
{
- return _liveTvManager.CloseLiveStream(liveStreamId, cancellationToken);
+ return _liveTvManager.CloseLiveStream(liveStreamId);
}
}
}
diff --git a/MediaBrowser.Server.Implementations/LiveTv/TunerHosts/BaseTunerHost.cs b/MediaBrowser.Server.Implementations/LiveTv/TunerHosts/BaseTunerHost.cs
index 6beea352a..a4236763f 100644
--- a/MediaBrowser.Server.Implementations/LiveTv/TunerHosts/BaseTunerHost.cs
+++ b/MediaBrowser.Server.Implementations/LiveTv/TunerHosts/BaseTunerHost.cs
@@ -73,7 +73,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv.TunerHosts
.ToList();
}
- public async Task> GetChannels(CancellationToken cancellationToken)
+ public async Task> GetChannels(bool enableCache, CancellationToken cancellationToken)
{
var list = new List();
@@ -83,7 +83,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv.TunerHosts
{
try
{
- var channels = await GetChannels(host, true, cancellationToken).ConfigureAwait(false);
+ var channels = await GetChannels(host, enableCache, cancellationToken).ConfigureAwait(false);
var newChannels = channels.Where(i => !list.Any(l => string.Equals(i.Id, l.Id, StringComparison.OrdinalIgnoreCase))).ToList();
list.AddRange(newChannels);
diff --git a/MediaBrowser.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunHost.cs b/MediaBrowser.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunHost.cs
index b40b74436..9f71940e1 100644
--- a/MediaBrowser.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunHost.cs
+++ b/MediaBrowser.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunHost.cs
@@ -67,14 +67,6 @@ namespace MediaBrowser.Server.Implementations.LiveTv.TunerHosts.HdHomerun
return id;
}
- public string ApplyDuration(string streamPath, TimeSpan duration)
- {
- streamPath += streamPath.IndexOf('?') == -1 ? "?" : "&";
- streamPath += "duration=" + Convert.ToInt32(duration.TotalSeconds).ToString(CultureInfo.InvariantCulture);
-
- return streamPath;
- }
-
private async Task> GetLineup(TunerHostInfo info, CancellationToken cancellationToken)
{
var options = new HttpRequestOptions
diff --git a/MediaBrowser.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunLiveStream.cs b/MediaBrowser.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunLiveStream.cs
index d3540d180..d6574db22 100644
--- a/MediaBrowser.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunLiveStream.cs
+++ b/MediaBrowser.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunLiveStream.cs
@@ -34,7 +34,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv.TunerHosts.HdHomerun
_appHost = appHost;
}
- public override async Task Open(CancellationToken openCancellationToken)
+ protected override async Task OpenInternal(CancellationToken openCancellationToken)
{
_liveStreamCancellationTokenSource.Token.ThrowIfCancellationRequested();
@@ -54,13 +54,14 @@ namespace MediaBrowser.Server.Implementations.LiveTv.TunerHosts.HdHomerun
await taskCompletionSource.Task.ConfigureAwait(false);
- PublicMediaSource.Path = _appHost.GetLocalApiUrl("localhost") + "/LiveTv/LiveStreamFiles/" + Path.GetFileNameWithoutExtension(tempFile) + "/stream.ts";
+ OpenedMediaSource.Path = _appHost.GetLocalApiUrl("localhost") + "/LiveTv/LiveStreamFiles/" + Path.GetFileNameWithoutExtension(tempFile) + "/stream.ts";
- PublicMediaSource.Protocol = MediaProtocol.Http;
+ OpenedMediaSource.Protocol = MediaProtocol.Http;
}
public override Task Close()
{
+ _logger.Info("Closing HDHR live stream");
_liveStreamCancellationTokenSource.Cancel();
return _liveStreamTaskCompletionSource.Task;
diff --git a/MediaBrowser.Server.Implementations/LiveTv/TunerHosts/M3UTunerHost.cs b/MediaBrowser.Server.Implementations/LiveTv/TunerHosts/M3UTunerHost.cs
index d9c0bb8bf..e5d6102b1 100644
--- a/MediaBrowser.Server.Implementations/LiveTv/TunerHosts/M3UTunerHost.cs
+++ b/MediaBrowser.Server.Implementations/LiveTv/TunerHosts/M3UTunerHost.cs
@@ -153,10 +153,5 @@ namespace MediaBrowser.Server.Implementations.LiveTv.TunerHosts
{
return Task.FromResult(true);
}
-
- public string ApplyDuration(string streamPath, TimeSpan duration)
- {
- return streamPath;
- }
}
}
diff --git a/MediaBrowser.Server.Implementations/Persistence/SqliteItemRepository.cs b/MediaBrowser.Server.Implementations/Persistence/SqliteItemRepository.cs
index 05c282687..097118418 100644
--- a/MediaBrowser.Server.Implementations/Persistence/SqliteItemRepository.cs
+++ b/MediaBrowser.Server.Implementations/Persistence/SqliteItemRepository.cs
@@ -2530,38 +2530,111 @@ namespace MediaBrowser.Server.Implementations.Persistence
whereClauses.Add("IsOffline=@IsOffline");
cmd.Parameters.Add(cmd, "@IsOffline", DbType.Boolean).Value = query.IsOffline;
}
- if (query.IsMovie.HasValue)
- {
- var alternateTypes = new List();
- if (query.IncludeItemTypes.Length == 0 || query.IncludeItemTypes.Contains(typeof(Movie).Name))
- {
- alternateTypes.Add(typeof(Movie).FullName);
- }
- if (query.IncludeItemTypes.Length == 0 || query.IncludeItemTypes.Contains(typeof(Trailer).Name))
- {
- alternateTypes.Add(typeof(Trailer).FullName);
- }
- if (alternateTypes.Count == 0)
- {
- whereClauses.Add("IsMovie=@IsMovie");
- }
- else
- {
- whereClauses.Add("(IsMovie is null OR IsMovie=@IsMovie)");
- }
- cmd.Parameters.Add(cmd, "@IsMovie", DbType.Boolean).Value = query.IsMovie;
- }
- if (query.IsKids.HasValue)
+ var exclusiveProgramAttribtues = !(query.IsMovie ?? true) ||
+ !(query.IsSports ?? true) ||
+ !(query.IsKids ?? true) ||
+ !(query.IsNews ?? true) ||
+ !(query.IsSeries ?? true);
+
+ if (exclusiveProgramAttribtues)
{
- whereClauses.Add("IsKids=@IsKids");
- cmd.Parameters.Add(cmd, "@IsKids", DbType.Boolean).Value = query.IsKids;
+ if (query.IsMovie.HasValue)
+ {
+ var alternateTypes = new List();
+ if (query.IncludeItemTypes.Length == 0 || query.IncludeItemTypes.Contains(typeof(Movie).Name))
+ {
+ alternateTypes.Add(typeof(Movie).FullName);
+ }
+ if (query.IncludeItemTypes.Length == 0 || query.IncludeItemTypes.Contains(typeof(Trailer).Name))
+ {
+ alternateTypes.Add(typeof(Trailer).FullName);
+ }
+
+ if (alternateTypes.Count == 0)
+ {
+ whereClauses.Add("IsMovie=@IsMovie");
+ cmd.Parameters.Add(cmd, "@IsMovie", DbType.Boolean).Value = query.IsMovie;
+ }
+ else
+ {
+ whereClauses.Add("(IsMovie is null OR IsMovie=@IsMovie)");
+ cmd.Parameters.Add(cmd, "@IsMovie", DbType.Boolean).Value = query.IsMovie;
+ }
+ }
+ if (query.IsSeries.HasValue)
+ {
+ whereClauses.Add("IsSeries=@IsSeries");
+ cmd.Parameters.Add(cmd, "@IsSeries", DbType.Boolean).Value = query.IsSeries;
+ }
+ if (query.IsNews.HasValue)
+ {
+ whereClauses.Add("IsNews=@IsNews");
+ cmd.Parameters.Add(cmd, "@IsNews", DbType.Boolean).Value = query.IsNews;
+ }
+ if (query.IsKids.HasValue)
+ {
+ whereClauses.Add("IsKids=@IsKids");
+ cmd.Parameters.Add(cmd, "@IsKids", DbType.Boolean).Value = query.IsKids;
+ }
+ if (query.IsSports.HasValue)
+ {
+ whereClauses.Add("IsSports=@IsSports");
+ cmd.Parameters.Add(cmd, "@IsSports", DbType.Boolean).Value = query.IsSports;
+ }
}
- if (query.IsSports.HasValue)
+ else
{
- whereClauses.Add("IsSports=@IsSports");
- cmd.Parameters.Add(cmd, "@IsSports", DbType.Boolean).Value = query.IsSports;
+ var programAttribtues = new List();
+ if (query.IsMovie ?? false)
+ {
+ var alternateTypes = new List();
+ if (query.IncludeItemTypes.Length == 0 || query.IncludeItemTypes.Contains(typeof(Movie).Name))
+ {
+ alternateTypes.Add(typeof(Movie).FullName);
+ }
+ if (query.IncludeItemTypes.Length == 0 || query.IncludeItemTypes.Contains(typeof(Trailer).Name))
+ {
+ alternateTypes.Add(typeof(Trailer).FullName);
+ }
+
+ if (alternateTypes.Count == 0)
+ {
+ programAttribtues.Add("IsMovie=@IsMovie");
+ }
+ else
+ {
+ programAttribtues.Add("(IsMovie is null OR IsMovie=@IsMovie)");
+ }
+
+ cmd.Parameters.Add(cmd, "@IsMovie", DbType.Boolean).Value = true;
+ }
+ if (query.IsSports ?? false)
+ {
+ programAttribtues.Add("IsSports=@IsSports");
+ cmd.Parameters.Add(cmd, "@IsSports", DbType.Boolean).Value = true;
+ }
+ if (query.IsNews ?? false)
+ {
+ programAttribtues.Add("IsNews=@IsNews");
+ cmd.Parameters.Add(cmd, "@IsNews", DbType.Boolean).Value = true;
+ }
+ if (query.IsSeries ?? false)
+ {
+ programAttribtues.Add("IsSeries=@IsSeries");
+ cmd.Parameters.Add(cmd, "@IsSeries", DbType.Boolean).Value = true;
+ }
+ if (query.IsKids ?? false)
+ {
+ programAttribtues.Add("IsKids=@IsKids");
+ cmd.Parameters.Add(cmd, "@IsKids", DbType.Boolean).Value = true;
+ }
+ if (programAttribtues.Count > 0)
+ {
+ whereClauses.Add("("+string.Join(" OR ", programAttribtues.ToArray())+")");
+ }
}
+
if (query.IsFolder.HasValue)
{
whereClauses.Add("IsFolder=@IsFolder");
diff --git a/MediaBrowser.Server.Implementations/Session/SessionManager.cs b/MediaBrowser.Server.Implementations/Session/SessionManager.cs
index 48f48cdcc..5857e9dbc 100644
--- a/MediaBrowser.Server.Implementations/Session/SessionManager.cs
+++ b/MediaBrowser.Server.Implementations/Session/SessionManager.cs
@@ -818,7 +818,7 @@ namespace MediaBrowser.Server.Implementations.Session
{
try
{
- await _mediaSourceManager.CloseLiveStream(info.LiveStreamId, CancellationToken.None).ConfigureAwait(false);
+ await _mediaSourceManager.CloseLiveStream(info.LiveStreamId).ConfigureAwait(false);
}
catch (Exception ex)
{
diff --git a/MediaBrowser.Server.Implementations/Sync/SyncedMediaSourceProvider.cs b/MediaBrowser.Server.Implementations/Sync/SyncedMediaSourceProvider.cs
index a2b5851ac..cb666b6ac 100644
--- a/MediaBrowser.Server.Implementations/Sync/SyncedMediaSourceProvider.cs
+++ b/MediaBrowser.Server.Implementations/Sync/SyncedMediaSourceProvider.cs
@@ -150,7 +150,7 @@ namespace MediaBrowser.Server.Implementations.Sync
}
}
- public Task CloseMediaSource(string liveStreamId, CancellationToken cancellationToken)
+ public Task CloseMediaSource(string liveStreamId)
{
throw new NotImplementedException();
}
diff --git a/MediaBrowser.WebDashboard/Api/DashboardService.cs b/MediaBrowser.WebDashboard/Api/DashboardService.cs
index 2f8b34879..4850b6fe0 100644
--- a/MediaBrowser.WebDashboard/Api/DashboardService.cs
+++ b/MediaBrowser.WebDashboard/Api/DashboardService.cs
@@ -289,7 +289,7 @@ namespace MediaBrowser.WebDashboard.Api
return list;
}
- private List> GetDeployIgnoreFilenames()
+ private List> GetDeployIgnoreFilenames()
{
var list = new List>();
@@ -313,8 +313,11 @@ namespace MediaBrowser.WebDashboard.Api
public async Task