support sharing m3u tuner streams

This commit is contained in:
Luke Pulverenti 2017-11-14 02:41:21 -05:00
parent 2c6cbb33ee
commit 2f758676d0
10 changed files with 78 additions and 19 deletions

View File

@ -404,11 +404,11 @@
<Compile Include="LiveTv\TunerHosts\BaseTunerHost.cs" /> <Compile Include="LiveTv\TunerHosts\BaseTunerHost.cs" />
<Compile Include="LiveTv\TunerHosts\HdHomerun\HdHomerunManager.cs" /> <Compile Include="LiveTv\TunerHosts\HdHomerun\HdHomerunManager.cs" />
<Compile Include="LiveTv\TunerHosts\HdHomerun\HdHomerunHost.cs" /> <Compile Include="LiveTv\TunerHosts\HdHomerun\HdHomerunHost.cs" />
<Compile Include="LiveTv\TunerHosts\HdHomerun\HdHomerunHttpStream.cs" />
<Compile Include="LiveTv\TunerHosts\HdHomerun\HdHomerunUdpStream.cs" /> <Compile Include="LiveTv\TunerHosts\HdHomerun\HdHomerunUdpStream.cs" />
<Compile Include="LiveTv\TunerHosts\LiveStream.cs" /> <Compile Include="LiveTv\TunerHosts\LiveStream.cs" />
<Compile Include="LiveTv\TunerHosts\M3uParser.cs" /> <Compile Include="LiveTv\TunerHosts\M3uParser.cs" />
<Compile Include="LiveTv\TunerHosts\M3UTunerHost.cs" /> <Compile Include="LiveTv\TunerHosts\M3UTunerHost.cs" />
<Compile Include="LiveTv\TunerHosts\SharedHttpStream.cs" />
<Compile Include="Localization\LocalizationManager.cs" /> <Compile Include="Localization\LocalizationManager.cs" />
<Compile Include="Localization\TextLocalizer.cs" /> <Compile Include="Localization\TextLocalizer.cs" />
<Compile Include="Logging\ConsoleLogger.cs" /> <Compile Include="Logging\ConsoleLogger.cs" />

View File

@ -618,7 +618,7 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts.HdHomerun
} }
mediaSource.Path = httpUrl; 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); return new HdHomerunUdpStream(mediaSource, streamId, new HdHomerunChannelCommands(hdhomerunChannel.Number, profile), modelInfo.TunerCount, FileSystem, _httpClient, Logger, Config.ApplicationPaths, _appHost, _socketFactory, _networkManager, _environment);

View File

@ -32,6 +32,7 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts.HdHomerun
OriginalStreamId = originalStreamId; OriginalStreamId = originalStreamId;
_channelCommands = channelCommands; _channelCommands = channelCommands;
_numTuners = numTuners; _numTuners = numTuners;
EnableStreamSharing = true;
} }
public override async Task Open(CancellationToken openCancellationToken) public override async Task Open(CancellationToken openCancellationToken)

View File

@ -29,8 +29,9 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts
public List<string> SharedStreamIds { get; private set; } public List<string> SharedStreamIds { get; private set; }
protected readonly IEnvironmentInfo Environment; protected readonly IEnvironmentInfo Environment;
protected readonly IFileSystem FileSystem; protected readonly IFileSystem FileSystem;
protected readonly IServerApplicationPaths AppPaths;
protected readonly string TempFilePath; protected string TempFilePath;
protected readonly ILogger Logger; protected readonly ILogger Logger;
protected readonly CancellationTokenSource LiveStreamCancellationTokenSource = new CancellationTokenSource(); protected readonly CancellationTokenSource LiveStreamCancellationTokenSource = new CancellationTokenSource();
@ -44,7 +45,15 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts
EnableStreamSharing = true; EnableStreamSharing = true;
SharedStreamIds = new List<string>(); SharedStreamIds = new List<string>();
UniqueId = Guid.NewGuid().ToString("N"); 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) public virtual Task Open(CancellationToken openCancellationToken)

View File

@ -79,8 +79,14 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts
{ {
var sources = await GetChannelStreamMediaSources(info, channelId, cancellationToken).ConfigureAwait(false); var sources = await GetChannelStreamMediaSources(info, channelId, cancellationToken).ConfigureAwait(false);
var liveStream = new LiveStream(sources.First(), _environment, FileSystem, Logger, Config.ApplicationPaths); var mediaSource = sources.First();
return liveStream;
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) public async Task Validate(TunerHostInfo info)

View File

@ -15,19 +15,20 @@ using MediaBrowser.Model.System;
using System.Globalization; using System.Globalization;
using MediaBrowser.Controller.IO; 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 IHttpClient _httpClient;
private readonly IServerApplicationHost _appHost; 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) : base(mediaSource, environment, fileSystem, logger, appPaths)
{ {
_httpClient = httpClient; _httpClient = httpClient;
_appHost = appHost; _appHost = appHost;
OriginalStreamId = originalStreamId; OriginalStreamId = originalStreamId;
EnableStreamSharing = true;
} }
public override async Task Open(CancellationToken openCancellationToken) public override async Task Open(CancellationToken openCancellationToken)
@ -40,7 +41,8 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts.HdHomerun
FileSystem.CreateDirectory(FileSystem.GetDirectoryName(TempFilePath)); 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 var response = await _httpClient.SendAsync(new HttpRequestOptions
{ {
@ -51,11 +53,35 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts.HdHomerun
// Increase a little bit // Increase a little bit
TimeoutMs = 30000, TimeoutMs = 30000,
EnableHttpCompression = false EnableHttpCompression = false,
LogResponse = true,
LogResponseHeaders = true
}, "GET").ConfigureAwait(false); }, "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<bool>(); var taskCompletionSource = new TaskCompletionSource<bool>();
StartStreaming(response, taskCompletionSource, LiveStreamCancellationTokenSource.Token); StartStreaming(response, taskCompletionSource, LiveStreamCancellationTokenSource.Token);
@ -90,7 +116,7 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts.HdHomerun
{ {
using (var stream = response.Content) 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)) using (var fileStream = FileSystem.GetFileStream(TempFilePath, FileOpenMode.Create, FileAccessMode.Write, FileShareMode.Read, FileOpenOptions.None))
{ {

View File

@ -335,7 +335,8 @@ namespace MediaBrowser.Api.Library
Fields = request.Fields, Fields = request.Fields,
Id = request.Id, Id = request.Id,
Limit = request.Limit, Limit = request.Limit,
UserId = request.UserId UserId = request.UserId,
ImageTypeLimit = request.ImageTypeLimit
}); });
} }
if (item is MusicAlbum) if (item is MusicAlbum)
@ -350,7 +351,8 @@ namespace MediaBrowser.Api.Library
Id = request.Id, Id = request.Id,
Limit = request.Limit, Limit = request.Limit,
UserId = request.UserId, UserId = request.UserId,
ExcludeArtistIds = request.ExcludeArtistIds ExcludeArtistIds = request.ExcludeArtistIds,
ImageTypeLimit = request.ImageTypeLimit
}); });
} }
if (item is MusicArtist) if (item is MusicArtist)
@ -364,7 +366,8 @@ namespace MediaBrowser.Api.Library
Fields = request.Fields, Fields = request.Fields,
Id = request.Id, Id = request.Id,
Limit = request.Limit, Limit = request.Limit,
UserId = request.UserId UserId = request.UserId,
ImageTypeLimit = request.ImageTypeLimit
}); });
} }
@ -381,7 +384,8 @@ namespace MediaBrowser.Api.Library
Fields = request.Fields, Fields = request.Fields,
Id = request.Id, Id = request.Id,
Limit = request.Limit, Limit = request.Limit,
UserId = request.UserId UserId = request.UserId,
ImageTypeLimit = request.ImageTypeLimit
}); });
} }
@ -396,7 +400,8 @@ namespace MediaBrowser.Api.Library
Fields = request.Fields, Fields = request.Fields,
Id = request.Id, Id = request.Id,
Limit = request.Limit, Limit = request.Limit,
UserId = request.UserId UserId = request.UserId,
ImageTypeLimit = request.ImageTypeLimit
}); });
} }

View File

@ -93,6 +93,8 @@ namespace MediaBrowser.Common.Net
public bool LogRequest { get; set; } public bool LogRequest { get; set; }
public bool LogRequestAsDebug { get; set; } public bool LogRequestAsDebug { get; set; }
public bool LogErrors { get; set; } public bool LogErrors { get; set; }
public bool LogResponse { get; set; }
public bool LogResponseHeaders { get; set; }
public bool LogErrorResponseBody { get; set; } public bool LogErrorResponseBody { get; set; }
public bool EnableKeepAlive { get; set; } public bool EnableKeepAlive { get; set; }

View File

@ -1421,6 +1421,16 @@ namespace MediaBrowser.Controller.Entities
// Sweep through recursively and update status // Sweep through recursively and update status
foreach (var item in itemsResult) 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); item.MarkPlayed(user, datePlayed, resetPosition);
} }
} }

View File

@ -1,3 +1,3 @@
using System.Reflection; using System.Reflection;
[assembly: AssemblyVersion("3.2.36.8")] [assembly: AssemblyVersion("3.2.36.9")]