aboutsummaryrefslogtreecommitdiff
path: root/Emby.Server.Implementations/LiveTv/TunerHosts
diff options
context:
space:
mode:
authorferferga <ferferga.fer@gmail.com>2020-10-19 17:28:07 +0200
committerferferga <ferferga.fer@gmail.com>2020-10-19 17:28:07 +0200
commit9fd01fade6ac971ba72a2e7dd54e2295f23839bc (patch)
tree20a5ff4a1621e765fc93c0e53b149edb61ff3654 /Emby.Server.Implementations/LiveTv/TunerHosts
parentba03ed65fe64b724b3e8b5b94b9cbe1075c61da2 (diff)
parent49ac4c4044b1777dc3a25544aead7b0b15b953e8 (diff)
Remove "download images in advance" option
Diffstat (limited to 'Emby.Server.Implementations/LiveTv/TunerHosts')
-rw-r--r--Emby.Server.Implementations/LiveTv/TunerHosts/BaseTunerHost.cs42
-rw-r--r--Emby.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunHost.cs182
-rw-r--r--Emby.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunManager.cs11
-rw-r--r--Emby.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunUdpStream.cs14
-rw-r--r--Emby.Server.Implementations/LiveTv/TunerHosts/LiveStream.cs5
-rw-r--r--Emby.Server.Implementations/LiveTv/TunerHosts/M3UTunerHost.cs22
-rw-r--r--Emby.Server.Implementations/LiveTv/TunerHosts/M3uParser.cs44
-rw-r--r--Emby.Server.Implementations/LiveTv/TunerHosts/SharedHttpStream.cs67
8 files changed, 193 insertions, 194 deletions
diff --git a/Emby.Server.Implementations/LiveTv/TunerHosts/BaseTunerHost.cs b/Emby.Server.Implementations/LiveTv/TunerHosts/BaseTunerHost.cs
index 80ee1ee33a..fbcd4ef372 100644
--- a/Emby.Server.Implementations/LiveTv/TunerHosts/BaseTunerHost.cs
+++ b/Emby.Server.Implementations/LiveTv/TunerHosts/BaseTunerHost.cs
@@ -1,10 +1,10 @@
#pragma warning disable CS1591
using System;
-using System.Collections.Concurrent;
using System.Collections.Generic;
using System.IO;
using System.Linq;
+using System.Text.Json;
using System.Threading;
using System.Threading.Tasks;
using MediaBrowser.Common.Configuration;
@@ -14,7 +14,7 @@ using MediaBrowser.Controller.LiveTv;
using MediaBrowser.Model.Dto;
using MediaBrowser.Model.IO;
using MediaBrowser.Model.LiveTv;
-using MediaBrowser.Model.Serialization;
+using Microsoft.Extensions.Caching.Memory;
using Microsoft.Extensions.Logging;
namespace Emby.Server.Implementations.LiveTv.TunerHosts
@@ -22,18 +22,16 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts
public abstract class BaseTunerHost
{
protected readonly IServerConfigurationManager Config;
- protected readonly ILogger Logger;
- protected IJsonSerializer JsonSerializer;
+ protected readonly ILogger<BaseTunerHost> Logger;
protected readonly IFileSystem FileSystem;
- private readonly ConcurrentDictionary<string, ChannelCache> _channelCache =
- new ConcurrentDictionary<string, ChannelCache>(StringComparer.OrdinalIgnoreCase);
+ private readonly IMemoryCache _memoryCache;
- protected BaseTunerHost(IServerConfigurationManager config, ILogger logger, IJsonSerializer jsonSerializer, IFileSystem fileSystem)
+ protected BaseTunerHost(IServerConfigurationManager config, ILogger<BaseTunerHost> logger, IFileSystem fileSystem, IMemoryCache memoryCache)
{
Config = config;
Logger = logger;
- JsonSerializer = jsonSerializer;
+ _memoryCache = memoryCache;
FileSystem = fileSystem;
}
@@ -44,23 +42,19 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts
public async Task<List<ChannelInfo>> GetChannels(TunerHostInfo tuner, bool enableCache, CancellationToken cancellationToken)
{
- ChannelCache cache = null;
var key = tuner.Id;
- if (enableCache && !string.IsNullOrEmpty(key) && _channelCache.TryGetValue(key, out cache))
+ if (enableCache && !string.IsNullOrEmpty(key) && _memoryCache.TryGetValue(key, out List<ChannelInfo> cache))
{
- return cache.Channels.ToList();
+ return cache;
}
- var result = await GetChannelsInternal(tuner, cancellationToken).ConfigureAwait(false);
- var list = result.ToList();
- //logger.LogInformation("Channels from {0}: {1}", tuner.Url, JsonSerializer.SerializeToString(list));
+ var list = await GetChannelsInternal(tuner, cancellationToken).ConfigureAwait(false);
+ // logger.LogInformation("Channels from {0}: {1}", tuner.Url, JsonSerializer.SerializeToString(list));
if (!string.IsNullOrEmpty(key) && list.Count > 0)
{
- cache = cache ?? new ChannelCache();
- cache.Channels = list;
- _channelCache.AddOrUpdate(key, cache, (k, v) => cache);
+ _memoryCache.Set(key, list);
}
return list;
@@ -95,11 +89,11 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts
try
{
Directory.CreateDirectory(Path.GetDirectoryName(channelCacheFile));
- JsonSerializer.SerializeToFile(channels, channelCacheFile);
+ await using var writeStream = File.OpenWrite(channelCacheFile);
+ await JsonSerializer.SerializeAsync(writeStream, channels, cancellationToken: cancellationToken).ConfigureAwait(false);
}
catch (IOException)
{
-
}
}
}
@@ -111,12 +105,13 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts
{
try
{
- var channels = JsonSerializer.DeserializeFromFile<List<ChannelInfo>>(channelCacheFile);
+ await using var readStream = File.OpenRead(channelCacheFile);
+ var channels = await JsonSerializer.DeserializeAsync<List<ChannelInfo>>(readStream, cancellationToken: cancellationToken)
+ .ConfigureAwait(false);
list.AddRange(channels);
}
catch (IOException)
{
-
}
}
}
@@ -235,10 +230,5 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts
{
return Config.GetConfiguration<LiveTvOptions>("livetv");
}
-
- private class ChannelCache
- {
- public List<ChannelInfo> Channels;
- }
}
}
diff --git a/Emby.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunHost.cs b/Emby.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunHost.cs
index 25b2c674c5..2f4c601172 100644
--- a/Emby.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunHost.cs
+++ b/Emby.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunHost.cs
@@ -7,6 +7,7 @@ using System.IO;
using System.Linq;
using System.Net;
using System.Net.Http;
+using System.Text.Json;
using System.Threading;
using System.Threading.Tasks;
using MediaBrowser.Common.Configuration;
@@ -23,32 +24,34 @@ using MediaBrowser.Model.IO;
using MediaBrowser.Model.LiveTv;
using MediaBrowser.Model.MediaInfo;
using MediaBrowser.Model.Net;
-using MediaBrowser.Model.Serialization;
+using Microsoft.Extensions.Caching.Memory;
using Microsoft.Extensions.Logging;
namespace Emby.Server.Implementations.LiveTv.TunerHosts.HdHomerun
{
public class HdHomerunHost : BaseTunerHost, ITunerHost, IConfigurableTunerHost
{
- private readonly IHttpClient _httpClient;
+ private readonly IHttpClientFactory _httpClientFactory;
private readonly IServerApplicationHost _appHost;
private readonly ISocketFactory _socketFactory;
private readonly INetworkManager _networkManager;
private readonly IStreamHelper _streamHelper;
+ private readonly Dictionary<string, DiscoverResponse> _modelCache = new Dictionary<string, DiscoverResponse>();
+
public HdHomerunHost(
IServerConfigurationManager config,
ILogger<HdHomerunHost> logger,
- IJsonSerializer jsonSerializer,
IFileSystem fileSystem,
- IHttpClient httpClient,
+ IHttpClientFactory httpClientFactory,
IServerApplicationHost appHost,
ISocketFactory socketFactory,
INetworkManager networkManager,
- IStreamHelper streamHelper)
- : base(config, logger, jsonSerializer, fileSystem)
+ IStreamHelper streamHelper,
+ IMemoryCache memoryCache)
+ : base(config, logger, fileSystem, memoryCache)
{
- _httpClient = httpClient;
+ _httpClientFactory = httpClientFactory;
_appHost = appHost;
_socketFactory = socketFactory;
_networkManager = networkManager;
@@ -68,25 +71,17 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts.HdHomerun
{
var model = await GetModelInfo(info, false, cancellationToken).ConfigureAwait(false);
- var options = new HttpRequestOptions
- {
- Url = model.LineupURL,
- CancellationToken = cancellationToken,
- BufferContent = false
- };
+ using var response = await _httpClientFactory.CreateClient(NamedClient.Default).GetAsync(model.LineupURL, HttpCompletionOption.ResponseHeadersRead, cancellationToken).ConfigureAwait(false);
+ await using var stream = await response.Content.ReadAsStreamAsync().ConfigureAwait(false);
+ var lineup = await JsonSerializer.DeserializeAsync<List<Channels>>(stream, cancellationToken: cancellationToken)
+ .ConfigureAwait(false) ?? new List<Channels>();
- using (var response = await _httpClient.SendAsync(options, HttpMethod.Get).ConfigureAwait(false))
- using (var stream = response.Content)
+ if (info.ImportFavoritesOnly)
{
- var lineup = await JsonSerializer.DeserializeFromStreamAsync<List<Channels>>(stream).ConfigureAwait(false) ?? new List<Channels>();
-
- if (info.ImportFavoritesOnly)
- {
- lineup = lineup.Where(i => i.Favorite).ToList();
- }
-
- return lineup.Where(i => !i.DRM).ToList();
+ lineup = lineup.Where(i => i.Favorite).ToList();
}
+
+ return lineup.Where(i => !i.DRM).ToList();
}
private class HdHomerunChannelInfo : ChannelInfo
@@ -111,11 +106,9 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts.HdHomerun
ChannelType = ChannelType.TV,
IsLegacyTuner = (i.URL ?? string.Empty).StartsWith("hdhomerun", StringComparison.OrdinalIgnoreCase),
Path = i.URL
-
}).Cast<ChannelInfo>().ToList();
}
- private readonly Dictionary<string, DiscoverResponse> _modelCache = new Dictionary<string, DiscoverResponse>();
private async Task<DiscoverResponse> GetModelInfo(TunerHostInfo info, bool throwAllExceptions, CancellationToken cancellationToken)
{
var cacheKey = info.Id;
@@ -133,35 +126,31 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts.HdHomerun
try
{
- using (var response = await _httpClient.SendAsync(new HttpRequestOptions()
- {
- Url = string.Format("{0}/discover.json", GetApiUrl(info)),
- CancellationToken = cancellationToken,
- BufferContent = false
- }, HttpMethod.Get).ConfigureAwait(false))
- using (var stream = response.Content)
- {
- var discoverResponse = await JsonSerializer.DeserializeFromStreamAsync<DiscoverResponse>(stream).ConfigureAwait(false);
+ using var response = await _httpClientFactory.CreateClient(NamedClient.Default)
+ .GetAsync(string.Format(CultureInfo.InvariantCulture, "{0}/discover.json", GetApiUrl(info)), HttpCompletionOption.ResponseHeadersRead, cancellationToken)
+ .ConfigureAwait(false);
+ await using var stream = await response.Content.ReadAsStreamAsync().ConfigureAwait(false);
+ var discoverResponse = await JsonSerializer.DeserializeAsync<DiscoverResponse>(stream, cancellationToken: cancellationToken)
+ .ConfigureAwait(false);
- if (!string.IsNullOrEmpty(cacheKey))
+ if (!string.IsNullOrEmpty(cacheKey))
+ {
+ lock (_modelCache)
{
- lock (_modelCache)
- {
- _modelCache[cacheKey] = discoverResponse;
- }
+ _modelCache[cacheKey] = discoverResponse;
}
-
- return discoverResponse;
}
+
+ return discoverResponse;
}
catch (HttpException ex)
{
- if (!throwAllExceptions && ex.StatusCode.HasValue && ex.StatusCode.Value == System.Net.HttpStatusCode.NotFound)
+ if (!throwAllExceptions && ex.StatusCode.HasValue && ex.StatusCode.Value == HttpStatusCode.NotFound)
{
- var defaultValue = "HDHR";
+ const string DefaultValue = "HDHR";
var response = new DiscoverResponse
{
- ModelNumber = defaultValue
+ ModelNumber = DefaultValue
};
if (!string.IsNullOrEmpty(cacheKey))
{
@@ -171,6 +160,7 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts.HdHomerun
_modelCache[cacheKey] = response;
}
}
+
return response;
}
@@ -182,42 +172,50 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts.HdHomerun
{
var model = await GetModelInfo(info, false, cancellationToken).ConfigureAwait(false);
- using (var response = await _httpClient.SendAsync(new HttpRequestOptions()
- {
- Url = string.Format("{0}/tuners.html", GetApiUrl(info)),
- CancellationToken = cancellationToken,
- BufferContent = false
- }, HttpMethod.Get).ConfigureAwait(false))
- using (var stream = response.Content)
- using (var sr = new StreamReader(stream, System.Text.Encoding.UTF8))
+ using var response = await _httpClientFactory.CreateClient(NamedClient.Default)
+ .GetAsync(string.Format(CultureInfo.InvariantCulture, "{0}/tuners.html", GetApiUrl(info)), HttpCompletionOption.ResponseHeadersRead, cancellationToken)
+ .ConfigureAwait(false);
+ await using var stream = await response.Content.ReadAsStreamAsync().ConfigureAwait(false);
+ using var sr = new StreamReader(stream, System.Text.Encoding.UTF8);
+ var tuners = new List<LiveTvTunerInfo>();
+ while (!sr.EndOfStream)
{
- var tuners = new List<LiveTvTunerInfo>();
- while (!sr.EndOfStream)
+ string line = StripXML(sr.ReadLine());
+ if (line.Contains("Channel", StringComparison.Ordinal))
{
- string line = StripXML(sr.ReadLine());
- if (line.Contains("Channel"))
+ LiveTvTunerStatus status;
+ var index = line.IndexOf("Channel", StringComparison.OrdinalIgnoreCase);
+ var name = line.Substring(0, index - 1);
+ var currentChannel = line.Substring(index + 7);
+ if (currentChannel != "none")
{
- LiveTvTunerStatus status;
- var index = line.IndexOf("Channel", StringComparison.OrdinalIgnoreCase);
- var name = line.Substring(0, index - 1);
- var currentChannel = line.Substring(index + 7);
- if (currentChannel != "none") { status = LiveTvTunerStatus.LiveTv; } else { status = LiveTvTunerStatus.Available; }
- tuners.Add(new LiveTvTunerInfo
- {
- Name = name,
- SourceType = string.IsNullOrWhiteSpace(model.ModelNumber) ? Name : model.ModelNumber,
- ProgramName = currentChannel,
- Status = status
- });
+ status = LiveTvTunerStatus.LiveTv;
+ }
+ else
+ {
+ status = LiveTvTunerStatus.Available;
}
- }
- return tuners;
+ tuners.Add(new LiveTvTunerInfo
+ {
+ Name = name,
+ SourceType = string.IsNullOrWhiteSpace(model.ModelNumber) ? Name : model.ModelNumber,
+ ProgramName = currentChannel,
+ Status = status
+ });
+ }
}
+
+ return tuners;
}
private static string StripXML(string source)
{
+ if (string.IsNullOrEmpty(source))
+ {
+ return string.Empty;
+ }
+
char[] buffer = new char[source.Length];
int bufferIndex = 0;
bool inside = false;
@@ -230,11 +228,13 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts.HdHomerun
inside = true;
continue;
}
+
if (let == '>')
{
inside = false;
continue;
}
+
if (!inside)
{
buffer[bufferIndex] = let;
@@ -260,7 +260,7 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts.HdHomerun
for (int i = 0; i < model.TunerCount; ++i)
{
- var name = string.Format("Tuner {0}", i + 1);
+ var name = string.Format(CultureInfo.InvariantCulture, "Tuner {0}", i + 1);
var currentChannel = "none"; // @todo Get current channel and map back to Station Id
var isAvailable = await manager.CheckTunerAvailability(ipInfo, i, cancellationToken).ConfigureAwait(false);
var status = isAvailable ? LiveTvTunerStatus.Available : LiveTvTunerStatus.LiveTv;
@@ -332,12 +332,19 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts.HdHomerun
private class Channels
{
public string GuideNumber { get; set; }
+
public string GuideName { get; set; }
+
public string VideoCodec { get; set; }
+
public string AudioCodec { get; set; }
+
public string URL { get; set; }
+
public bool Favorite { get; set; }
+
public bool DRM { get; set; }
+
public int HD { get; set; }
}
@@ -481,7 +488,6 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts.HdHomerun
Height = height,
BitRate = videoBitrate,
NalLengthSize = nal
-
},
new MediaStream
{
@@ -502,8 +508,8 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts.HdHomerun
SupportsTranscoding = true,
IsInfiniteStream = true,
IgnoreDts = true,
- //IgnoreIndex = true,
- //ReadAtNativeFramerate = true
+ // IgnoreIndex = true,
+ // ReadAtNativeFramerate = true
};
mediaSource.InferTotalBitrate();
@@ -557,6 +563,19 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts.HdHomerun
protected override async Task<ILiveStream> GetChannelStream(TunerHostInfo info, ChannelInfo channelInfo, string streamId, List<ILiveStream> currentLiveStreams, CancellationToken cancellationToken)
{
+ var tunerCount = info.TunerCount;
+
+ if (tunerCount > 0)
+ {
+ var tunerHostId = info.Id;
+ var liveStreams = currentLiveStreams.Where(i => string.Equals(i.TunerHostId, tunerHostId, StringComparison.OrdinalIgnoreCase));
+
+ if (liveStreams.Count() >= tunerCount)
+ {
+ throw new LiveTvConflictException("HDHomeRun simultaneous stream limit has been reached.");
+ }
+ }
+
var profile = streamId.Split('_')[0];
Logger.LogInformation("GetChannelStream: channel id: {0}. stream id: {1} profile: {2}", channelInfo.Id, streamId, profile);
@@ -610,7 +629,7 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts.HdHomerun
info,
streamId,
FileSystem,
- _httpClient,
+ _httpClientFactory,
Logger,
Config,
_appHost,
@@ -659,13 +678,21 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts.HdHomerun
public class DiscoverResponse
{
public string FriendlyName { get; set; }
+
public string ModelNumber { get; set; }
+
public string FirmwareName { get; set; }
+
public string FirmwareVersion { get; set; }
+
public string DeviceID { get; set; }
+
public string DeviceAuth { get; set; }
+
public string BaseURL { get; set; }
+
public string LineupURL { get; set; }
+
public int TunerCount { get; set; }
public bool SupportsTranscoding
@@ -674,7 +701,7 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts.HdHomerun
{
var model = ModelNumber ?? string.Empty;
- if ((model.IndexOf("hdtc", StringComparison.OrdinalIgnoreCase) != -1))
+ if (model.IndexOf("hdtc", StringComparison.OrdinalIgnoreCase) != -1)
{
return true;
}
@@ -701,7 +728,7 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts.HdHomerun
// Need a way to set the Receive timeout on the socket otherwise this might never timeout?
try
{
- await udpClient.SendToAsync(discBytes, 0, discBytes.Length, new IPEndPoint(IPAddress.Parse("255.255.255.255"), 65001), cancellationToken);
+ await udpClient.SendToAsync(discBytes, 0, discBytes.Length, new IPEndPoint(IPAddress.Parse("255.255.255.255"), 65001), cancellationToken).ConfigureAwait(false);
var receiveBuffer = new byte[8192];
while (!cancellationToken.IsCancellationRequested)
@@ -722,7 +749,6 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts.HdHomerun
}
}
}
-
}
catch (OperationCanceledException)
{
diff --git a/Emby.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunManager.cs b/Emby.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunManager.cs
index 57c5b75002..d4a88e299f 100644
--- a/Emby.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunManager.cs
+++ b/Emby.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunManager.cs
@@ -77,7 +77,7 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts.HdHomerun
}
}
- public class HdHomerunManager : IDisposable
+ public sealed class HdHomerunManager : IDisposable
{
public const int HdHomeRunPort = 65001;
@@ -105,6 +105,8 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts.HdHomerun
StopStreaming(socket).GetAwaiter().GetResult();
}
}
+
+ GC.SuppressFinalize(this);
}
public async Task<bool> CheckTunerAvailability(IPAddress remoteIp, int tuner, CancellationToken cancellationToken)
@@ -162,7 +164,7 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts.HdHomerun
}
_activeTuner = i;
- var lockKeyString = string.Format("{0:d}", lockKeyValue);
+ var lockKeyString = string.Format(CultureInfo.InvariantCulture, "{0:d}", lockKeyValue);
var lockkeyMsg = CreateSetMessage(i, "lockkey", lockKeyString, null);
await stream.WriteAsync(lockkeyMsg, 0, lockkeyMsg.Length, cancellationToken).ConfigureAwait(false);
int receivedBytes = await stream.ReadAsync(buffer, 0, buffer.Length, cancellationToken).ConfigureAwait(false);
@@ -173,8 +175,7 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts.HdHomerun
continue;
}
- var commandList = commands.GetCommands();
- foreach (var command in commandList)
+ foreach (var command in commands.GetCommands())
{
var channelMsg = CreateSetMessage(i, command.Item1, command.Item2, lockKeyValue);
await stream.WriteAsync(channelMsg, 0, channelMsg.Length, cancellationToken).ConfigureAwait(false);
@@ -188,7 +189,7 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts.HdHomerun
}
}
- var targetValue = string.Format("rtp://{0}:{1}", localIp, localPort);
+ var targetValue = string.Format(CultureInfo.InvariantCulture, "rtp://{0}:{1}", localIp, localPort);
var targetMsg = CreateSetMessage(i, "target", targetValue, lockKeyValue);
await stream.WriteAsync(targetMsg, 0, targetMsg.Length, cancellationToken).ConfigureAwait(false);
diff --git a/Emby.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunUdpStream.cs b/Emby.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunUdpStream.cs
index 82b1f3cf1f..6730751d50 100644
--- a/Emby.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunUdpStream.cs
+++ b/Emby.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunUdpStream.cs
@@ -117,17 +117,17 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts.HdHomerun
taskCompletionSource,
LiveStreamCancellationTokenSource.Token).ConfigureAwait(false);
- //OpenedMediaSource.Protocol = MediaProtocol.File;
- //OpenedMediaSource.Path = tempFile;
- //OpenedMediaSource.ReadAtNativeFramerate = true;
+ // OpenedMediaSource.Protocol = MediaProtocol.File;
+ // OpenedMediaSource.Path = tempFile;
+ // OpenedMediaSource.ReadAtNativeFramerate = true;
MediaSource.Path = _appHost.GetLoopbackHttpApiUrl() + "/LiveTv/LiveStreamFiles/" + UniqueId + "/stream.ts";
MediaSource.Protocol = MediaProtocol.Http;
- //OpenedMediaSource.SupportsDirectPlay = false;
- //OpenedMediaSource.SupportsDirectStream = true;
- //OpenedMediaSource.SupportsTranscoding = true;
+ // OpenedMediaSource.SupportsDirectPlay = false;
+ // OpenedMediaSource.SupportsDirectStream = true;
+ // OpenedMediaSource.SupportsTranscoding = true;
- //await Task.Delay(5000).ConfigureAwait(false);
+ // await Task.Delay(5000).ConfigureAwait(false);
await taskCompletionSource.Task.ConfigureAwait(false);
}
diff --git a/Emby.Server.Implementations/LiveTv/TunerHosts/LiveStream.cs b/Emby.Server.Implementations/LiveTv/TunerHosts/LiveStream.cs
index 4e4f1d7f60..0333e723bc 100644
--- a/Emby.Server.Implementations/LiveTv/TunerHosts/LiveStream.cs
+++ b/Emby.Server.Implementations/LiveTv/TunerHosts/LiveStream.cs
@@ -58,12 +58,15 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts
protected virtual int EmptyReadLimit => 1000;
public MediaSourceInfo OriginalMediaSource { get; set; }
+
public MediaSourceInfo MediaSource { get; set; }
public int ConsumerCount { get; set; }
public string OriginalStreamId { get; set; }
+
public bool EnableStreamSharing { get; set; }
+
public string UniqueId { get; }
public string TunerHostId { get; }
@@ -220,11 +223,9 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts
}
catch (IOException)
{
-
}
catch (ArgumentException)
{
-
}
catch (Exception ex)
{
diff --git a/Emby.Server.Implementations/LiveTv/TunerHosts/M3UTunerHost.cs b/Emby.Server.Implementations/LiveTv/TunerHosts/M3UTunerHost.cs
index f7c9c736e3..8107bc427b 100644
--- a/Emby.Server.Implementations/LiveTv/TunerHosts/M3UTunerHost.cs
+++ b/Emby.Server.Implementations/LiveTv/TunerHosts/M3UTunerHost.cs
@@ -5,6 +5,7 @@ using System.Collections.Generic;
using System.Globalization;
using System.IO;
using System.Linq;
+using System.Net.Http;
using System.Threading;
using System.Threading.Tasks;
using MediaBrowser.Common.Extensions;
@@ -18,7 +19,7 @@ using MediaBrowser.Model.Entities;
using MediaBrowser.Model.IO;
using MediaBrowser.Model.LiveTv;
using MediaBrowser.Model.MediaInfo;
-using MediaBrowser.Model.Serialization;
+using Microsoft.Extensions.Caching.Memory;
using Microsoft.Extensions.Logging;
using Microsoft.Net.Http.Headers;
@@ -26,7 +27,7 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts
{
public class M3UTunerHost : BaseTunerHost, ITunerHost, IConfigurableTunerHost
{
- private readonly IHttpClient _httpClient;
+ private readonly IHttpClientFactory _httpClientFactory;
private readonly IServerApplicationHost _appHost;
private readonly INetworkManager _networkManager;
private readonly IMediaSourceManager _mediaSourceManager;
@@ -36,15 +37,15 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts
IServerConfigurationManager config,
IMediaSourceManager mediaSourceManager,
ILogger<M3UTunerHost> logger,
- IJsonSerializer jsonSerializer,
IFileSystem fileSystem,
- IHttpClient httpClient,
+ IHttpClientFactory httpClientFactory,
IServerApplicationHost appHost,
INetworkManager networkManager,
- IStreamHelper streamHelper)
- : base(config, logger, jsonSerializer, fileSystem)
+ IStreamHelper streamHelper,
+ IMemoryCache memoryCache)
+ : base(config, logger, fileSystem, memoryCache)
{
- _httpClient = httpClient;
+ _httpClientFactory = httpClientFactory;
_appHost = appHost;
_networkManager = networkManager;
_mediaSourceManager = mediaSourceManager;
@@ -64,7 +65,7 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts
{
var channelIdPrefix = GetFullChannelIdPrefix(info);
- return await new M3uParser(Logger, _httpClient, _appHost).Parse(info.Url, channelIdPrefix, info.Id, cancellationToken).ConfigureAwait(false);
+ return await new M3uParser(Logger, _httpClientFactory, _appHost).Parse(info.Url, channelIdPrefix, info.Id, cancellationToken).ConfigureAwait(false);
}
public Task<List<LiveTvTunerInfo>> GetTunerInfos(CancellationToken cancellationToken)
@@ -116,7 +117,7 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts
if (!_disallowedSharedStreamExtensions.Contains(extension, StringComparer.OrdinalIgnoreCase))
{
- return new SharedHttpStream(mediaSource, info, streamId, FileSystem, _httpClient, Logger, Config, _appHost, _streamHelper);
+ return new SharedHttpStream(mediaSource, info, streamId, FileSystem, _httpClientFactory, Logger, Config, _appHost, _streamHelper);
}
}
@@ -125,9 +126,8 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts
public async Task Validate(TunerHostInfo info)
{
- using (var stream = await new M3uParser(Logger, _httpClient, _appHost).GetListingsStream(info.Url, CancellationToken.None).ConfigureAwait(false))
+ using (var stream = await new M3uParser(Logger, _httpClientFactory, _appHost).GetListingsStream(info.Url, CancellationToken.None).ConfigureAwait(false))
{
-
}
}
diff --git a/Emby.Server.Implementations/LiveTv/TunerHosts/M3uParser.cs b/Emby.Server.Implementations/LiveTv/TunerHosts/M3uParser.cs
index 59451fccd2..f066a749e3 100644
--- a/Emby.Server.Implementations/LiveTv/TunerHosts/M3uParser.cs
+++ b/Emby.Server.Implementations/LiveTv/TunerHosts/M3uParser.cs
@@ -5,6 +5,7 @@ using System.Collections.Generic;
using System.Globalization;
using System.IO;
using System.Linq;
+using System.Net.Http;
using System.Text.RegularExpressions;
using System.Threading;
using System.Threading.Tasks;
@@ -19,13 +20,13 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts
public class M3uParser
{
private readonly ILogger _logger;
- private readonly IHttpClient _httpClient;
+ private readonly IHttpClientFactory _httpClientFactory;
private readonly IServerApplicationHost _appHost;
- public M3uParser(ILogger logger, IHttpClient httpClient, IServerApplicationHost appHost)
+ public M3uParser(ILogger logger, IHttpClientFactory httpClientFactory, IServerApplicationHost appHost)
{
_logger = logger;
- _httpClient = httpClient;
+ _httpClientFactory = httpClientFactory;
_appHost = appHost;
}
@@ -51,13 +52,8 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts
{
if (url.StartsWith("http", StringComparison.OrdinalIgnoreCase))
{
- return _httpClient.Get(new HttpRequestOptions
- {
- Url = url,
- CancellationToken = cancellationToken,
- // Some data providers will require a user agent
- UserAgent = _appHost.ApplicationUserAgent
- });
+ return _httpClientFactory.CreateClient(NamedClient.Default)
+ .GetStreamAsync(url);
}
return Task.FromResult((Stream)File.OpenRead(url));
@@ -158,15 +154,14 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts
private string GetChannelNumber(string extInf, Dictionary<string, string> attributes, string mediaUrl)
{
var nameParts = extInf.Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries);
- var nameInExtInf = nameParts.Length > 1 ? nameParts[nameParts.Length - 1].Trim() : null;
+ var nameInExtInf = nameParts.Length > 1 ? nameParts[^1].AsSpan().Trim() : ReadOnlySpan<char>.Empty;
string numberString = null;
string attributeValue;
- double doubleValue;
if (attributes.TryGetValue("tvg-chno", out attributeValue))
{
- if (double.TryParse(attributeValue, NumberStyles.Any, CultureInfo.InvariantCulture, out doubleValue))
+ if (double.TryParse(attributeValue, NumberStyles.Any, CultureInfo.InvariantCulture, out _))
{
numberString = attributeValue;
}
@@ -176,41 +171,40 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts
{
if (attributes.TryGetValue("tvg-id", out attributeValue))
{
- if (double.TryParse(attributeValue, NumberStyles.Any, CultureInfo.InvariantCulture, out doubleValue))
+ if (double.TryParse(attributeValue, NumberStyles.Any, CultureInfo.InvariantCulture, out _))
{
numberString = attributeValue;
}
else if (attributes.TryGetValue("channel-id", out attributeValue))
{
- if (double.TryParse(attributeValue, NumberStyles.Any, CultureInfo.InvariantCulture, out doubleValue))
+ if (double.TryParse(attributeValue, NumberStyles.Any, CultureInfo.InvariantCulture, out _))
{
numberString = attributeValue;
}
}
}
- if (String.IsNullOrWhiteSpace(numberString))
+ if (string.IsNullOrWhiteSpace(numberString))
{
// Using this as a fallback now as this leads to Problems with channels like "5 USA"
// where 5 isnt ment to be the channel number
// Check for channel number with the format from SatIp
// #EXTINF:0,84. VOX Schweiz
// #EXTINF:0,84.0 - VOX Schweiz
- if (!string.IsNullOrWhiteSpace(nameInExtInf))
+ if (!nameInExtInf.IsEmpty && !nameInExtInf.IsWhiteSpace())
{
var numberIndex = nameInExtInf.IndexOf(' ');
if (numberIndex > 0)
{
- var numberPart = nameInExtInf.Substring(0, numberIndex).Trim(new[] { ' ', '.' });
+ var numberPart = nameInExtInf.Slice(0, numberIndex).Trim(new[] { ' ', '.' });
- if (double.TryParse(numberPart, NumberStyles.Any, CultureInfo.InvariantCulture, out var number))
+ if (double.TryParse(numberPart, NumberStyles.Any, CultureInfo.InvariantCulture, out _))
{
- numberString = numberPart;
+ numberString = numberPart.ToString();
}
}
}
}
-
}
if (!IsValidChannelNumber(numberString))
@@ -232,7 +226,7 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts
{
try
{
- numberString = Path.GetFileNameWithoutExtension(mediaUrl.Split('/').Last());
+ numberString = Path.GetFileNameWithoutExtension(mediaUrl.Split('/')[^1]);
if (!IsValidChannelNumber(numberString))
{
@@ -259,7 +253,7 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts
return false;
}
- if (!double.TryParse(numberString, NumberStyles.Any, CultureInfo.InvariantCulture, out var value))
+ if (!double.TryParse(numberString, NumberStyles.Any, CultureInfo.InvariantCulture, out _))
{
return false;
}
@@ -282,9 +276,9 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts
{
var numberPart = nameInExtInf.Substring(0, numberIndex).Trim(new[] { ' ', '.' });
- if (double.TryParse(numberPart, NumberStyles.Any, CultureInfo.InvariantCulture, out var number))
+ if (double.TryParse(numberPart, NumberStyles.Any, CultureInfo.InvariantCulture, out _))
{
- //channel.Number = number.ToString();
+ // channel.Number = number.ToString();
nameInExtInf = nameInExtInf.Substring(numberIndex + 1).Trim(new[] { ' ', '-' });
}
}
diff --git a/Emby.Server.Implementations/LiveTv/TunerHosts/SharedHttpStream.cs b/Emby.Server.Implementations/LiveTv/TunerHosts/SharedHttpStream.cs
index 322fbbbaa5..6c10fca8c6 100644
--- a/Emby.Server.Implementations/LiveTv/TunerHosts/SharedHttpStream.cs
+++ b/Emby.Server.Implementations/LiveTv/TunerHosts/SharedHttpStream.cs
@@ -21,7 +21,7 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts
{
public class SharedHttpStream : LiveStream, IDirectStreamProvider
{
- private readonly IHttpClient _httpClient;
+ private readonly IHttpClientFactory _httpClientFactory;
private readonly IServerApplicationHost _appHost;
public SharedHttpStream(
@@ -29,14 +29,14 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts
TunerHostInfo tunerHostInfo,
string originalStreamId,
IFileSystem fileSystem,
- IHttpClient httpClient,
+ IHttpClientFactory httpClientFactory,
ILogger logger,
IConfigurationManager configurationManager,
IServerApplicationHost appHost,
IStreamHelper streamHelper)
: base(mediaSource, tunerHostInfo, fileSystem, logger, configurationManager, streamHelper)
{
- _httpClient = httpClient;
+ _httpClientFactory = httpClientFactory;
_appHost = appHost;
OriginalStreamId = originalStreamId;
EnableStreamSharing = true;
@@ -55,25 +55,14 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts
var typeName = GetType().Name;
Logger.LogInformation("Opening " + typeName + " Live stream from {0}", url);
- var httpRequestOptions = new HttpRequestOptions
- {
- Url = url,
- CancellationToken = CancellationToken.None,
- BufferContent = false,
- DecompressionMethod = CompressionMethods.None
- };
-
- foreach (var header in mediaSource.RequiredHttpHeaders)
- {
- httpRequestOptions.RequestHeaders[header.Key] = header.Value;
- }
-
- var response = await _httpClient.SendAsync(httpRequestOptions, HttpMethod.Get).ConfigureAwait(false);
+ using var response = await _httpClientFactory.CreateClient(NamedClient.Default)
+ .GetAsync(url, HttpCompletionOption.ResponseHeadersRead, CancellationToken.None)
+ .ConfigureAwait(false);
var extension = "ts";
var requiresRemux = false;
- var contentType = response.ContentType ?? string.Empty;
+ var contentType = response.Content.Headers.ContentType.ToString();
if (contentType.IndexOf("matroska", StringComparison.OrdinalIgnoreCase) != -1)
{
requiresRemux = true;
@@ -103,21 +92,21 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts
_ = StartStreaming(response, taskCompletionSource, LiveStreamCancellationTokenSource.Token);
- //OpenedMediaSource.Protocol = MediaProtocol.File;
- //OpenedMediaSource.Path = tempFile;
- //OpenedMediaSource.ReadAtNativeFramerate = true;
+ // OpenedMediaSource.Protocol = MediaProtocol.File;
+ // OpenedMediaSource.Path = tempFile;
+ // OpenedMediaSource.ReadAtNativeFramerate = true;
MediaSource.Path = _appHost.GetLoopbackHttpApiUrl() + "/LiveTv/LiveStreamFiles/" + UniqueId + "/stream.ts";
MediaSource.Protocol = MediaProtocol.Http;
- //OpenedMediaSource.Path = TempFilePath;
- //OpenedMediaSource.Protocol = MediaProtocol.File;
+ // OpenedMediaSource.Path = TempFilePath;
+ // OpenedMediaSource.Protocol = MediaProtocol.File;
- //OpenedMediaSource.Path = _tempFilePath;
- //OpenedMediaSource.Protocol = MediaProtocol.File;
- //OpenedMediaSource.SupportsDirectPlay = false;
- //OpenedMediaSource.SupportsDirectStream = true;
- //OpenedMediaSource.SupportsTranscoding = true;
+ // OpenedMediaSource.Path = _tempFilePath;
+ // OpenedMediaSource.Protocol = MediaProtocol.File;
+ // OpenedMediaSource.SupportsDirectPlay = false;
+ // OpenedMediaSource.SupportsDirectStream = true;
+ // OpenedMediaSource.SupportsTranscoding = true;
await taskCompletionSource.Task.ConfigureAwait(false);
if (taskCompletionSource.Task.Exception != null)
{
@@ -132,24 +121,22 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts
}
}
- private Task StartStreaming(HttpResponseInfo response, TaskCompletionSource<bool> openTaskCompletionSource, CancellationToken cancellationToken)
+ private Task StartStreaming(HttpResponseMessage response, TaskCompletionSource<bool> openTaskCompletionSource, CancellationToken cancellationToken)
{
return Task.Run(async () =>
{
try
{
Logger.LogInformation("Beginning {0} stream to {1}", GetType().Name, TempFilePath);
- using (response)
- using (var stream = response.Content)
- using (var fileStream = new FileStream(TempFilePath, FileMode.Create, FileAccess.Write, FileShare.Read))
- {
- await StreamHelper.CopyToAsync(
- stream,
- fileStream,
- IODefaults.CopyToBufferSize,
- () => Resolve(openTaskCompletionSource),
- cancellationToken).ConfigureAwait(false);
- }
+ using var message = response;
+ await using var stream = await response.Content.ReadAsStreamAsync().ConfigureAwait(false);
+ await using var fileStream = new FileStream(TempFilePath, FileMode.Create, FileAccess.Write, FileShare.Read);
+ await StreamHelper.CopyToAsync(
+ stream,
+ fileStream,
+ IODefaults.CopyToBufferSize,
+ () => Resolve(openTaskCompletionSource),
+ cancellationToken).ConfigureAwait(false);
}
catch (OperationCanceledException ex)
{