From 2f758676d0908f07dafc3ec5434bbaf4cf82529c Mon Sep 17 00:00:00 2001 From: Luke Pulverenti Date: Tue, 14 Nov 2017 02:41:21 -0500 Subject: [PATCH] support sharing m3u tuner streams --- .../Emby.Server.Implementations.csproj | 2 +- .../TunerHosts/HdHomerun/HdHomerunHost.cs | 2 +- .../HdHomerun/HdHomerunUdpStream.cs | 1 + .../LiveTv/TunerHosts/LiveStream.cs | 13 +++++- .../LiveTv/TunerHosts/M3UTunerHost.cs | 10 ++++- ...merunHttpStream.cs => SharedHttpStream.cs} | 40 +++++++++++++++---- MediaBrowser.Api/Library/LibraryService.cs | 15 ++++--- MediaBrowser.Common/Net/HttpRequestOptions.cs | 2 + MediaBrowser.Controller/Entities/Folder.cs | 10 +++++ SharedVersion.cs | 2 +- 10 files changed, 78 insertions(+), 19 deletions(-) rename Emby.Server.Implementations/LiveTv/TunerHosts/{HdHomerun/HdHomerunHttpStream.cs => SharedHttpStream.cs} (71%) diff --git a/Emby.Server.Implementations/Emby.Server.Implementations.csproj b/Emby.Server.Implementations/Emby.Server.Implementations.csproj index 6b2a005f9f..7ccf54d20f 100644 --- a/Emby.Server.Implementations/Emby.Server.Implementations.csproj +++ b/Emby.Server.Implementations/Emby.Server.Implementations.csproj @@ -404,11 +404,11 @@ - + diff --git a/Emby.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunHost.cs b/Emby.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunHost.cs index 8cfe9de39c..08eab9a35b 100644 --- a/Emby.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunHost.cs +++ b/Emby.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunHost.cs @@ -618,7 +618,7 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts.HdHomerun } mediaSource.Path = httpUrl; - return new HdHomerunHttpStream(mediaSource, streamId, FileSystem, _httpClient, Logger, Config.ApplicationPaths, _appHost, _environment); + return new SharedHttpStream(mediaSource, streamId, FileSystem, _httpClient, Logger, Config.ApplicationPaths, _appHost, _environment); } return new HdHomerunUdpStream(mediaSource, streamId, new HdHomerunChannelCommands(hdhomerunChannel.Number, profile), modelInfo.TunerCount, FileSystem, _httpClient, Logger, Config.ApplicationPaths, _appHost, _socketFactory, _networkManager, _environment); diff --git a/Emby.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunUdpStream.cs b/Emby.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunUdpStream.cs index 8b46b78be9..a329300804 100644 --- a/Emby.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunUdpStream.cs +++ b/Emby.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunUdpStream.cs @@ -32,6 +32,7 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts.HdHomerun OriginalStreamId = originalStreamId; _channelCommands = channelCommands; _numTuners = numTuners; + EnableStreamSharing = true; } public override async Task Open(CancellationToken openCancellationToken) diff --git a/Emby.Server.Implementations/LiveTv/TunerHosts/LiveStream.cs b/Emby.Server.Implementations/LiveTv/TunerHosts/LiveStream.cs index cead1def03..bec92716bb 100644 --- a/Emby.Server.Implementations/LiveTv/TunerHosts/LiveStream.cs +++ b/Emby.Server.Implementations/LiveTv/TunerHosts/LiveStream.cs @@ -29,8 +29,9 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts public List SharedStreamIds { get; private set; } protected readonly IEnvironmentInfo Environment; protected readonly IFileSystem FileSystem; + protected readonly IServerApplicationPaths AppPaths; - protected readonly string TempFilePath; + protected string TempFilePath; protected readonly ILogger Logger; protected readonly CancellationTokenSource LiveStreamCancellationTokenSource = new CancellationTokenSource(); @@ -44,7 +45,15 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts EnableStreamSharing = true; SharedStreamIds = new List(); UniqueId = Guid.NewGuid().ToString("N"); - TempFilePath = Path.Combine(appPaths.GetTranscodingTempPath(), UniqueId + ".ts"); + + AppPaths = appPaths; + + SetTempFilePath("ts"); + } + + protected void SetTempFilePath(string extension) + { + TempFilePath = Path.Combine(AppPaths.GetTranscodingTempPath(), UniqueId + "." + extension); } public virtual Task Open(CancellationToken openCancellationToken) diff --git a/Emby.Server.Implementations/LiveTv/TunerHosts/M3UTunerHost.cs b/Emby.Server.Implementations/LiveTv/TunerHosts/M3UTunerHost.cs index 9fc6687d14..e41fb7fbeb 100644 --- a/Emby.Server.Implementations/LiveTv/TunerHosts/M3UTunerHost.cs +++ b/Emby.Server.Implementations/LiveTv/TunerHosts/M3UTunerHost.cs @@ -79,8 +79,14 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts { var sources = await GetChannelStreamMediaSources(info, channelId, cancellationToken).ConfigureAwait(false); - var liveStream = new LiveStream(sources.First(), _environment, FileSystem, Logger, Config.ApplicationPaths); - return liveStream; + var mediaSource = sources.First(); + + if (mediaSource.Protocol == MediaProtocol.Http && !mediaSource.RequiresLooping) + { + return new SharedHttpStream(mediaSource, streamId, FileSystem, _httpClient, Logger, Config.ApplicationPaths, _appHost, _environment); + } + + return new LiveStream(mediaSource, _environment, FileSystem, Logger, Config.ApplicationPaths); } public async Task Validate(TunerHostInfo info) diff --git a/Emby.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunHttpStream.cs b/Emby.Server.Implementations/LiveTv/TunerHosts/SharedHttpStream.cs similarity index 71% rename from Emby.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunHttpStream.cs rename to Emby.Server.Implementations/LiveTv/TunerHosts/SharedHttpStream.cs index ddbbda7374..a33b0945b9 100644 --- a/Emby.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunHttpStream.cs +++ b/Emby.Server.Implementations/LiveTv/TunerHosts/SharedHttpStream.cs @@ -15,19 +15,20 @@ using MediaBrowser.Model.System; using System.Globalization; using MediaBrowser.Controller.IO; -namespace Emby.Server.Implementations.LiveTv.TunerHosts.HdHomerun +namespace Emby.Server.Implementations.LiveTv.TunerHosts { - public class HdHomerunHttpStream : LiveStream, IDirectStreamProvider + public class SharedHttpStream : LiveStream, IDirectStreamProvider { private readonly IHttpClient _httpClient; private readonly IServerApplicationHost _appHost; - public HdHomerunHttpStream(MediaSourceInfo mediaSource, string originalStreamId, IFileSystem fileSystem, IHttpClient httpClient, ILogger logger, IServerApplicationPaths appPaths, IServerApplicationHost appHost, IEnvironmentInfo environment) + public SharedHttpStream(MediaSourceInfo mediaSource, string originalStreamId, IFileSystem fileSystem, IHttpClient httpClient, ILogger logger, IServerApplicationPaths appPaths, IServerApplicationHost appHost, IEnvironmentInfo environment) : base(mediaSource, environment, fileSystem, logger, appPaths) { _httpClient = httpClient; _appHost = appHost; OriginalStreamId = originalStreamId; + EnableStreamSharing = true; } public override async Task Open(CancellationToken openCancellationToken) @@ -40,7 +41,8 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts.HdHomerun FileSystem.CreateDirectory(FileSystem.GetDirectoryName(TempFilePath)); - Logger.Info("Opening HDHR Live stream from {0}", url); + var typeName = GetType().Name; + Logger.Info("Opening " + typeName + " Live stream from {0}", url); var response = await _httpClient.SendAsync(new HttpRequestOptions { @@ -51,11 +53,35 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts.HdHomerun // Increase a little bit TimeoutMs = 30000, - EnableHttpCompression = false + EnableHttpCompression = false, + + LogResponse = true, + LogResponseHeaders = true }, "GET").ConfigureAwait(false); - Logger.Info("Opened HDHR stream from {0}", url); + var extension = "ts"; + var requiresRemux = false; + + var contentType = response.ContentType ?? string.Empty; + if (contentType.IndexOf("mp4", StringComparison.OrdinalIgnoreCase) != -1 || + contentType.IndexOf("matroska", StringComparison.OrdinalIgnoreCase) != -1 || + contentType.IndexOf("dash", StringComparison.OrdinalIgnoreCase) != -1 || + contentType.IndexOf("mpegURL", StringComparison.OrdinalIgnoreCase) != -1) + { + requiresRemux = true; + } + + // Close the stream without any sharing features + if (requiresRemux) + { + using (response) + { + return; + } + } + + SetTempFilePath(extension); var taskCompletionSource = new TaskCompletionSource(); StartStreaming(response, taskCompletionSource, LiveStreamCancellationTokenSource.Token); @@ -90,7 +116,7 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts.HdHomerun { using (var stream = response.Content) { - Logger.Info("Beginning HdHomerunHttpStream stream to file"); + Logger.Info("Beginning {0} stream to {1}", GetType().Name, TempFilePath); using (var fileStream = FileSystem.GetFileStream(TempFilePath, FileOpenMode.Create, FileAccessMode.Write, FileShareMode.Read, FileOpenOptions.None)) { diff --git a/MediaBrowser.Api/Library/LibraryService.cs b/MediaBrowser.Api/Library/LibraryService.cs index 6152ea20b8..a036a00a6e 100644 --- a/MediaBrowser.Api/Library/LibraryService.cs +++ b/MediaBrowser.Api/Library/LibraryService.cs @@ -335,7 +335,8 @@ namespace MediaBrowser.Api.Library Fields = request.Fields, Id = request.Id, Limit = request.Limit, - UserId = request.UserId + UserId = request.UserId, + ImageTypeLimit = request.ImageTypeLimit }); } if (item is MusicAlbum) @@ -350,7 +351,8 @@ namespace MediaBrowser.Api.Library Id = request.Id, Limit = request.Limit, UserId = request.UserId, - ExcludeArtistIds = request.ExcludeArtistIds + ExcludeArtistIds = request.ExcludeArtistIds, + ImageTypeLimit = request.ImageTypeLimit }); } if (item is MusicArtist) @@ -364,7 +366,8 @@ namespace MediaBrowser.Api.Library Fields = request.Fields, Id = request.Id, Limit = request.Limit, - UserId = request.UserId + UserId = request.UserId, + ImageTypeLimit = request.ImageTypeLimit }); } @@ -381,7 +384,8 @@ namespace MediaBrowser.Api.Library Fields = request.Fields, Id = request.Id, Limit = request.Limit, - UserId = request.UserId + UserId = request.UserId, + ImageTypeLimit = request.ImageTypeLimit }); } @@ -396,7 +400,8 @@ namespace MediaBrowser.Api.Library Fields = request.Fields, Id = request.Id, Limit = request.Limit, - UserId = request.UserId + UserId = request.UserId, + ImageTypeLimit = request.ImageTypeLimit }); } diff --git a/MediaBrowser.Common/Net/HttpRequestOptions.cs b/MediaBrowser.Common/Net/HttpRequestOptions.cs index 0a279fa9cc..8f0b155f34 100644 --- a/MediaBrowser.Common/Net/HttpRequestOptions.cs +++ b/MediaBrowser.Common/Net/HttpRequestOptions.cs @@ -93,6 +93,8 @@ namespace MediaBrowser.Common.Net public bool LogRequest { get; set; } public bool LogRequestAsDebug { get; set; } public bool LogErrors { get; set; } + public bool LogResponse { get; set; } + public bool LogResponseHeaders { get; set; } public bool LogErrorResponseBody { get; set; } public bool EnableKeepAlive { get; set; } diff --git a/MediaBrowser.Controller/Entities/Folder.cs b/MediaBrowser.Controller/Entities/Folder.cs index fb283067f3..504d03a276 100644 --- a/MediaBrowser.Controller/Entities/Folder.cs +++ b/MediaBrowser.Controller/Entities/Folder.cs @@ -1421,6 +1421,16 @@ namespace MediaBrowser.Controller.Entities // Sweep through recursively and update status foreach (var item in itemsResult) { + if (item.IsVirtualItem) + { + // The querying doesn't support virtual unaired + var episode = item as Episode; + if (episode != null && episode.IsUnaired) + { + continue; + } + } + item.MarkPlayed(user, datePlayed, resetPosition); } } diff --git a/SharedVersion.cs b/SharedVersion.cs index c89077695c..812369b17f 100644 --- a/SharedVersion.cs +++ b/SharedVersion.cs @@ -1,3 +1,3 @@ using System.Reflection; -[assembly: AssemblyVersion("3.2.36.8")] +[assembly: AssemblyVersion("3.2.36.9")]