aboutsummaryrefslogtreecommitdiff
path: root/MediaBrowser.Server.Implementations/LiveTv/TunerHosts
diff options
context:
space:
mode:
authorLuke Pulverenti <luke.pulverenti@gmail.com>2016-11-03 19:35:19 -0400
committerLuke Pulverenti <luke.pulverenti@gmail.com>2016-11-03 19:35:19 -0400
commitd5ea8ca3ad378fc7e0a18ad314e1dfce07003ab6 (patch)
tree4742a665e3455389a9795ff8b6c292263b3876e8 /MediaBrowser.Server.Implementations/LiveTv/TunerHosts
parentd0babf322dad6624ee15622d11db52e58db5197f (diff)
move classes to portable
Diffstat (limited to 'MediaBrowser.Server.Implementations/LiveTv/TunerHosts')
-rw-r--r--MediaBrowser.Server.Implementations/LiveTv/TunerHosts/BaseTunerHost.cs249
-rw-r--r--MediaBrowser.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunDiscovery.cs159
-rw-r--r--MediaBrowser.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunHost.cs570
-rw-r--r--MediaBrowser.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunLiveStream.cs147
-rw-r--r--MediaBrowser.Server.Implementations/LiveTv/TunerHosts/M3UTunerHost.cs167
-rw-r--r--MediaBrowser.Server.Implementations/LiveTv/TunerHosts/M3uParser.cs169
-rw-r--r--MediaBrowser.Server.Implementations/LiveTv/TunerHosts/MulticastStream.cs96
-rw-r--r--MediaBrowser.Server.Implementations/LiveTv/TunerHosts/QueueStream.cs93
-rw-r--r--MediaBrowser.Server.Implementations/LiveTv/TunerHosts/SatIp/SatIpHost.cs2
9 files changed, 1 insertions, 1651 deletions
diff --git a/MediaBrowser.Server.Implementations/LiveTv/TunerHosts/BaseTunerHost.cs b/MediaBrowser.Server.Implementations/LiveTv/TunerHosts/BaseTunerHost.cs
deleted file mode 100644
index 0fe74798f5..0000000000
--- a/MediaBrowser.Server.Implementations/LiveTv/TunerHosts/BaseTunerHost.cs
+++ /dev/null
@@ -1,249 +0,0 @@
-using MediaBrowser.Common.Configuration;
-using MediaBrowser.Controller.LiveTv;
-using MediaBrowser.Model.Dto;
-using MediaBrowser.Model.LiveTv;
-using MediaBrowser.Model.Logging;
-using System;
-using System.Collections.Concurrent;
-using System.Collections.Generic;
-using System.IO;
-using System.Linq;
-using System.Threading;
-using System.Threading.Tasks;
-using MediaBrowser.Controller.Configuration;
-using MediaBrowser.Controller.MediaEncoding;
-using MediaBrowser.Model.Dlna;
-using MediaBrowser.Model.Serialization;
-
-namespace MediaBrowser.Server.Implementations.LiveTv.TunerHosts
-{
- public abstract class BaseTunerHost
- {
- protected readonly IServerConfigurationManager Config;
- protected readonly ILogger Logger;
- protected IJsonSerializer JsonSerializer;
- protected readonly IMediaEncoder MediaEncoder;
-
- private readonly ConcurrentDictionary<string, ChannelCache> _channelCache =
- new ConcurrentDictionary<string, ChannelCache>(StringComparer.OrdinalIgnoreCase);
-
- protected BaseTunerHost(IServerConfigurationManager config, ILogger logger, IJsonSerializer jsonSerializer, IMediaEncoder mediaEncoder)
- {
- Config = config;
- Logger = logger;
- JsonSerializer = jsonSerializer;
- MediaEncoder = mediaEncoder;
- }
-
- protected abstract Task<IEnumerable<ChannelInfo>> GetChannelsInternal(TunerHostInfo tuner, CancellationToken cancellationToken);
- public abstract string Type { get; }
-
- public async Task<IEnumerable<ChannelInfo>> GetChannels(TunerHostInfo tuner, bool enableCache, CancellationToken cancellationToken)
- {
- ChannelCache cache = null;
- var key = tuner.Id;
-
- if (enableCache && !string.IsNullOrWhiteSpace(key) && _channelCache.TryGetValue(key, out cache))
- {
- if (DateTime.UtcNow - cache.Date < TimeSpan.FromMinutes(60))
- {
- return cache.Channels.ToList();
- }
- }
-
- var result = await GetChannelsInternal(tuner, cancellationToken).ConfigureAwait(false);
- var list = result.ToList();
- Logger.Debug("Channels from {0}: {1}", tuner.Url, JsonSerializer.SerializeToString(list));
-
- if (!string.IsNullOrWhiteSpace(key) && list.Count > 0)
- {
- cache = cache ?? new ChannelCache();
- cache.Date = DateTime.UtcNow;
- cache.Channels = list;
- _channelCache.AddOrUpdate(key, cache, (k, v) => cache);
- }
-
- return list;
- }
-
- protected virtual List<TunerHostInfo> GetTunerHosts()
- {
- return GetConfiguration().TunerHosts
- .Where(i => i.IsEnabled && string.Equals(i.Type, Type, StringComparison.OrdinalIgnoreCase))
- .ToList();
- }
-
- public async Task<IEnumerable<ChannelInfo>> GetChannels(bool enableCache, CancellationToken cancellationToken)
- {
- var list = new List<ChannelInfo>();
-
- var hosts = GetTunerHosts();
-
- foreach (var host in hosts)
- {
- try
- {
- 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);
- }
- catch (Exception ex)
- {
- Logger.ErrorException("Error getting channel list", ex);
- }
- }
-
- return list;
- }
-
- protected abstract Task<List<MediaSourceInfo>> GetChannelStreamMediaSources(TunerHostInfo tuner, string channelId, CancellationToken cancellationToken);
-
- public async Task<List<MediaSourceInfo>> GetChannelStreamMediaSources(string channelId, CancellationToken cancellationToken)
- {
- if (IsValidChannelId(channelId))
- {
- var hosts = GetTunerHosts();
-
- var hostsWithChannel = new List<TunerHostInfo>();
-
- foreach (var host in hosts)
- {
- try
- {
- var channels = await GetChannels(host, true, cancellationToken).ConfigureAwait(false);
-
- if (channels.Any(i => string.Equals(i.Id, channelId, StringComparison.OrdinalIgnoreCase)))
- {
- hostsWithChannel.Add(host);
- }
- }
- catch (Exception ex)
- {
- Logger.Error("Error getting channels", ex);
- }
- }
-
- foreach (var host in hostsWithChannel)
- {
- try
- {
- // Check to make sure the tuner is available
- // If there's only one tuner, don't bother with the check and just let the tuner be the one to throw an error
- if (hostsWithChannel.Count > 1 &&
- !await IsAvailable(host, channelId, cancellationToken).ConfigureAwait(false))
- {
- Logger.Error("Tuner is not currently available");
- continue;
- }
-
- var mediaSources = await GetChannelStreamMediaSources(host, channelId, cancellationToken).ConfigureAwait(false);
-
- // Prefix the id with the host Id so that we can easily find it
- foreach (var mediaSource in mediaSources)
- {
- mediaSource.Id = host.Id + mediaSource.Id;
- }
-
- return mediaSources;
- }
- catch (Exception ex)
- {
- Logger.Error("Error opening tuner", ex);
- }
- }
- }
-
- return new List<MediaSourceInfo>();
- }
-
- protected abstract Task<LiveStream> GetChannelStream(TunerHostInfo tuner, string channelId, string streamId, CancellationToken cancellationToken);
-
- public async Task<LiveStream> GetChannelStream(string channelId, string streamId, CancellationToken cancellationToken)
- {
- if (!IsValidChannelId(channelId))
- {
- throw new FileNotFoundException();
- }
-
- var hosts = GetTunerHosts();
-
- var hostsWithChannel = new List<TunerHostInfo>();
-
- foreach (var host in hosts)
- {
- if (string.IsNullOrWhiteSpace(streamId))
- {
- try
- {
- var channels = await GetChannels(host, true, cancellationToken).ConfigureAwait(false);
-
- if (channels.Any(i => string.Equals(i.Id, channelId, StringComparison.OrdinalIgnoreCase)))
- {
- hostsWithChannel.Add(host);
- }
- }
- catch (Exception ex)
- {
- Logger.Error("Error getting channels", ex);
- }
- }
- else if (streamId.StartsWith(host.Id, StringComparison.OrdinalIgnoreCase))
- {
- hostsWithChannel = new List<TunerHostInfo> { host };
- streamId = streamId.Substring(host.Id.Length);
- break;
- }
- }
-
- foreach (var host in hostsWithChannel)
- {
- try
- {
- var liveStream = await GetChannelStream(host, channelId, streamId, cancellationToken).ConfigureAwait(false);
- await liveStream.Open(cancellationToken).ConfigureAwait(false);
- return liveStream;
- }
- catch (Exception ex)
- {
- Logger.Error("Error opening tuner", ex);
- }
- }
-
- throw new LiveTvConflictException();
- }
-
- protected virtual bool EnableMediaProbing
- {
- get { return false; }
- }
-
- protected async Task<bool> IsAvailable(TunerHostInfo tuner, string channelId, CancellationToken cancellationToken)
- {
- try
- {
- return await IsAvailableInternal(tuner, channelId, cancellationToken).ConfigureAwait(false);
- }
- catch (Exception ex)
- {
- Logger.ErrorException("Error checking tuner availability", ex);
- return false;
- }
- }
-
- protected abstract Task<bool> IsAvailableInternal(TunerHostInfo tuner, string channelId, CancellationToken cancellationToken);
-
- protected abstract bool IsValidChannelId(string channelId);
-
- protected LiveTvOptions GetConfiguration()
- {
- return Config.GetConfiguration<LiveTvOptions>("livetv");
- }
-
- private class ChannelCache
- {
- public DateTime Date;
- public List<ChannelInfo> Channels;
- }
- }
-}
diff --git a/MediaBrowser.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunDiscovery.cs b/MediaBrowser.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunDiscovery.cs
deleted file mode 100644
index f039da9274..0000000000
--- a/MediaBrowser.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunDiscovery.cs
+++ /dev/null
@@ -1,159 +0,0 @@
-using MediaBrowser.Common.Configuration;
-using MediaBrowser.Controller.Configuration;
-using MediaBrowser.Controller.Dlna;
-using MediaBrowser.Controller.LiveTv;
-using MediaBrowser.Controller.Plugins;
-using MediaBrowser.Model.Extensions;
-using MediaBrowser.Model.LiveTv;
-using MediaBrowser.Model.Logging;
-using System;
-using System.Linq;
-using System.Threading;
-using MediaBrowser.Common.Net;
-using MediaBrowser.Model.Dlna;
-using MediaBrowser.Model.Events;
-using MediaBrowser.Model.Serialization;
-
-namespace MediaBrowser.Server.Implementations.LiveTv.TunerHosts.HdHomerun
-{
- public class HdHomerunDiscovery : IServerEntryPoint
- {
- private readonly IDeviceDiscovery _deviceDiscovery;
- private readonly IServerConfigurationManager _config;
- private readonly ILogger _logger;
- private readonly ILiveTvManager _liveTvManager;
- private readonly SemaphoreSlim _semaphore = new SemaphoreSlim(1, 1);
- private readonly IHttpClient _httpClient;
- private readonly IJsonSerializer _json;
-
- public HdHomerunDiscovery(IDeviceDiscovery deviceDiscovery, IServerConfigurationManager config, ILogger logger, ILiveTvManager liveTvManager, IHttpClient httpClient, IJsonSerializer json)
- {
- _deviceDiscovery = deviceDiscovery;
- _config = config;
- _logger = logger;
- _liveTvManager = liveTvManager;
- _httpClient = httpClient;
- _json = json;
- }
-
- public void Run()
- {
- _deviceDiscovery.DeviceDiscovered += _deviceDiscovery_DeviceDiscovered;
- }
-
- void _deviceDiscovery_DeviceDiscovered(object sender, GenericEventArgs<UpnpDeviceInfo> e)
- {
- string server = null;
- var info = e.Argument;
-
- if (info.Headers.TryGetValue("SERVER", out server) && server.IndexOf("HDHomeRun", StringComparison.OrdinalIgnoreCase) != -1)
- {
- string location;
- if (info.Headers.TryGetValue("Location", out location))
- {
- //_logger.Debug("HdHomerun found at {0}", location);
-
- // Just get the beginning of the url
- Uri uri;
- if (Uri.TryCreate(location, UriKind.Absolute, out uri))
- {
- var apiUrl = location.Replace(uri.LocalPath, String.Empty, StringComparison.OrdinalIgnoreCase)
- .TrimEnd('/');
-
- //_logger.Debug("HdHomerun api url: {0}", apiUrl);
- AddDevice(apiUrl);
- }
- }
- }
- }
-
- private async void AddDevice(string url)
- {
- await _semaphore.WaitAsync().ConfigureAwait(false);
-
- try
- {
- var options = GetConfiguration();
-
- if (options.TunerHosts.Any(i =>
- string.Equals(i.Type, HdHomerunHost.DeviceType, StringComparison.OrdinalIgnoreCase) &&
- UriEquals(i.Url, url)))
- {
- return;
- }
-
- // Strip off the port
- url = new Uri(url).GetComponents(UriComponents.AbsoluteUri & ~UriComponents.Port, UriFormat.UriEscaped).TrimEnd('/');
-
- // Test it by pulling down the lineup
- using (var stream = await _httpClient.Get(new HttpRequestOptions
- {
- Url = string.Format("{0}/discover.json", url),
- CancellationToken = CancellationToken.None,
- BufferContent = false
- }))
- {
- var response = _json.DeserializeFromStream<HdHomerunHost.DiscoverResponse>(stream);
-
- var existing = GetConfiguration().TunerHosts
- .FirstOrDefault(i => string.Equals(i.Type, HdHomerunHost.DeviceType, StringComparison.OrdinalIgnoreCase) && string.Equals(i.DeviceId, response.DeviceID, StringComparison.OrdinalIgnoreCase));
-
- if (existing == null)
- {
- await _liveTvManager.SaveTunerHost(new TunerHostInfo
- {
- Type = HdHomerunHost.DeviceType,
- Url = url,
- DataVersion = 1,
- DeviceId = response.DeviceID
-
- }).ConfigureAwait(false);
- }
- else
- {
- if (!string.Equals(existing.Url, url, StringComparison.OrdinalIgnoreCase))
- {
- existing.Url = url;
- await _liveTvManager.SaveTunerHost(existing).ConfigureAwait(false);
- }
- }
- }
- }
- catch (Exception ex)
- {
- _logger.ErrorException("Error saving device", ex);
- }
- finally
- {
- _semaphore.Release();
- }
- }
-
- private bool UriEquals(string savedUri, string location)
- {
- return string.Equals(NormalizeUrl(location), NormalizeUrl(savedUri), StringComparison.OrdinalIgnoreCase);
- }
-
- private string NormalizeUrl(string url)
- {
- if (!url.StartsWith("http", StringComparison.OrdinalIgnoreCase))
- {
- url = "http://" + url;
- }
-
- url = url.TrimEnd('/');
-
- // Strip off the port
- return new Uri(url).GetComponents(UriComponents.AbsoluteUri & ~UriComponents.Port, UriFormat.UriEscaped);
- }
-
- private LiveTvOptions GetConfiguration()
- {
- return _config.GetConfiguration<LiveTvOptions>("livetv");
- }
-
- public void Dispose()
- {
- }
- }
-}
diff --git a/MediaBrowser.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunHost.cs b/MediaBrowser.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunHost.cs
deleted file mode 100644
index a32f4cca23..0000000000
--- a/MediaBrowser.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunHost.cs
+++ /dev/null
@@ -1,570 +0,0 @@
-using MediaBrowser.Common.Configuration;
-using MediaBrowser.Common.Net;
-using MediaBrowser.Controller.LiveTv;
-using MediaBrowser.Model.Dto;
-using MediaBrowser.Model.Entities;
-using MediaBrowser.Model.LiveTv;
-using MediaBrowser.Model.Logging;
-using MediaBrowser.Model.MediaInfo;
-using MediaBrowser.Model.Serialization;
-using System;
-using System.Collections.Generic;
-using System.Globalization;
-using System.IO;
-using System.Linq;
-using System.Threading;
-using System.Threading.Tasks;
-using MediaBrowser.Model.IO;
-using MediaBrowser.Common.Extensions;
-using MediaBrowser.Common.IO;
-using MediaBrowser.Controller;
-using MediaBrowser.Controller.Configuration;
-using MediaBrowser.Controller.IO;
-using MediaBrowser.Controller.MediaEncoding;
-using MediaBrowser.Model.Configuration;
-using MediaBrowser.Model.Net;
-
-namespace MediaBrowser.Server.Implementations.LiveTv.TunerHosts.HdHomerun
-{
- public class HdHomerunHost : BaseTunerHost, ITunerHost, IConfigurableTunerHost
- {
- private readonly IHttpClient _httpClient;
- private readonly IFileSystem _fileSystem;
- private readonly IServerApplicationHost _appHost;
-
- public HdHomerunHost(IServerConfigurationManager config, ILogger logger, IJsonSerializer jsonSerializer, IMediaEncoder mediaEncoder, IHttpClient httpClient, IFileSystem fileSystem, IServerApplicationHost appHost)
- : base(config, logger, jsonSerializer, mediaEncoder)
- {
- _httpClient = httpClient;
- _fileSystem = fileSystem;
- _appHost = appHost;
- }
-
- public string Name
- {
- get { return "HD Homerun"; }
- }
-
- public override string Type
- {
- get { return DeviceType; }
- }
-
- public static string DeviceType
- {
- get { return "hdhomerun"; }
- }
-
- private const string ChannelIdPrefix = "hdhr_";
-
- private string GetChannelId(TunerHostInfo info, Channels i)
- {
- var id = ChannelIdPrefix + i.GuideNumber.ToString(CultureInfo.InvariantCulture);
-
- if (info.DataVersion >= 1)
- {
- id += '_' + (i.GuideName ?? string.Empty).GetMD5().ToString("N");
- }
-
- return id;
- }
-
- private async Task<IEnumerable<Channels>> GetLineup(TunerHostInfo info, CancellationToken cancellationToken)
- {
- var options = new HttpRequestOptions
- {
- Url = string.Format("{0}/lineup.json", GetApiUrl(info, false)),
- CancellationToken = cancellationToken,
- BufferContent = false
- };
- using (var stream = await _httpClient.Get(options))
- {
- var lineup = JsonSerializer.DeserializeFromStream<List<Channels>>(stream) ?? new List<Channels>();
-
- if (info.ImportFavoritesOnly)
- {
- lineup = lineup.Where(i => i.Favorite).ToList();
- }
-
- return lineup.Where(i => !i.DRM).ToList();
- }
- }
-
- protected override async Task<IEnumerable<ChannelInfo>> GetChannelsInternal(TunerHostInfo info, CancellationToken cancellationToken)
- {
- var lineup = await GetLineup(info, cancellationToken).ConfigureAwait(false);
-
- return lineup.Select(i => new ChannelInfo
- {
- Name = i.GuideName,
- Number = i.GuideNumber.ToString(CultureInfo.InvariantCulture),
- Id = GetChannelId(info, i),
- IsFavorite = i.Favorite,
- TunerHostId = info.Id,
- IsHD = i.HD == 1,
- AudioCodec = i.AudioCodec,
- VideoCodec = i.VideoCodec
- });
- }
-
- private readonly Dictionary<string, DiscoverResponse> _modelCache = new Dictionary<string, DiscoverResponse>();
- private async Task<string> GetModelInfo(TunerHostInfo info, CancellationToken cancellationToken)
- {
- lock (_modelCache)
- {
- DiscoverResponse response;
- if (_modelCache.TryGetValue(info.Url, out response))
- {
- return response.ModelNumber;
- }
- }
-
- try
- {
- using (var stream = await _httpClient.Get(new HttpRequestOptions()
- {
- Url = string.Format("{0}/discover.json", GetApiUrl(info, false)),
- CancellationToken = cancellationToken,
- CacheLength = TimeSpan.FromDays(1),
- CacheMode = CacheMode.Unconditional,
- TimeoutMs = Convert.ToInt32(TimeSpan.FromSeconds(5).TotalMilliseconds),
- BufferContent = false
- }))
- {
- var response = JsonSerializer.DeserializeFromStream<DiscoverResponse>(stream);
-
- lock (_modelCache)
- {
- _modelCache[info.Id] = response;
- }
-
- return response.ModelNumber;
- }
- }
- catch (HttpException ex)
- {
- if (ex.StatusCode.HasValue && ex.StatusCode.Value == System.Net.HttpStatusCode.NotFound)
- {
- var defaultValue = "HDHR";
- // HDHR4 doesn't have this api
- lock (_modelCache)
- {
- _modelCache[info.Id] = new DiscoverResponse
- {
- ModelNumber = defaultValue
- };
- }
- return defaultValue;
- }
-
- throw;
- }
- }
-
- public async Task<List<LiveTvTunerInfo>> GetTunerInfos(TunerHostInfo info, CancellationToken cancellationToken)
- {
- var model = await GetModelInfo(info, cancellationToken).ConfigureAwait(false);
-
- using (var stream = await _httpClient.Get(new HttpRequestOptions()
- {
- Url = string.Format("{0}/tuners.html", GetApiUrl(info, false)),
- CancellationToken = cancellationToken,
- TimeoutMs = Convert.ToInt32(TimeSpan.FromSeconds(5).TotalMilliseconds),
- BufferContent = false
- }))
- {
- var tuners = new List<LiveTvTunerInfo>();
- using (var sr = new StreamReader(stream, System.Text.Encoding.UTF8))
- {
- while (!sr.EndOfStream)
- {
- 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") { status = LiveTvTunerStatus.LiveTv; } else { status = LiveTvTunerStatus.Available; }
- tuners.Add(new LiveTvTunerInfo
- {
- Name = name,
- SourceType = string.IsNullOrWhiteSpace(model) ? Name : model,
- ProgramName = currentChannel,
- Status = status
- });
- }
- }
- }
- return tuners;
- }
- }
-
- public async Task<List<LiveTvTunerInfo>> GetTunerInfos(CancellationToken cancellationToken)
- {
- var list = new List<LiveTvTunerInfo>();
-
- foreach (var host in GetConfiguration().TunerHosts
- .Where(i => i.IsEnabled && string.Equals(i.Type, Type, StringComparison.OrdinalIgnoreCase)))
- {
- try
- {
- list.AddRange(await GetTunerInfos(host, cancellationToken).ConfigureAwait(false));
- }
- catch (Exception ex)
- {
- Logger.ErrorException("Error getting tuner info", ex);
- }
- }
-
- return list;
- }
-
- private string GetApiUrl(TunerHostInfo info, bool isPlayback)
- {
- var url = info.Url;
-
- if (string.IsNullOrWhiteSpace(url))
- {
- throw new ArgumentException("Invalid tuner info");
- }
-
- if (!url.StartsWith("http", StringComparison.OrdinalIgnoreCase))
- {
- url = "http://" + url;
- }
-
- var uri = new Uri(url);
-
- if (isPlayback)
- {
- var builder = new UriBuilder(uri);
- builder.Port = 5004;
- uri = builder.Uri;
- }
-
- return uri.AbsoluteUri.TrimEnd('/');
- }
-
- private static string StripXML(string source)
- {
- char[] buffer = new char[source.Length];
- int bufferIndex = 0;
- bool inside = false;
-
- for (int i = 0; i < source.Length; i++)
- {
- char let = source[i];
- if (let == '<')
- {
- inside = true;
- continue;
- }
- if (let == '>')
- {
- inside = false;
- continue;
- }
- if (!inside)
- {
- buffer[bufferIndex] = let;
- bufferIndex++;
- }
- }
- return new string(buffer, 0, bufferIndex);
- }
-
- 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; }
- }
-
- private async Task<MediaSourceInfo> GetMediaSource(TunerHostInfo info, string channelId, string profile)
- {
- int? width = null;
- int? height = null;
- bool isInterlaced = true;
- string videoCodec = null;
- string audioCodec = "ac3";
-
- int? videoBitrate = null;
- int? audioBitrate = null;
-
- if (string.Equals(profile, "mobile", StringComparison.OrdinalIgnoreCase))
- {
- width = 1280;
- height = 720;
- isInterlaced = false;
- videoCodec = "h264";
- videoBitrate = 2000000;
- }
- else if (string.Equals(profile, "heavy", StringComparison.OrdinalIgnoreCase))
- {
- width = 1920;
- height = 1080;
- isInterlaced = false;
- videoCodec = "h264";
- videoBitrate = 15000000;
- }
- else if (string.Equals(profile, "internet540", StringComparison.OrdinalIgnoreCase))
- {
- width = 960;
- height = 546;
- isInterlaced = false;
- videoCodec = "h264";
- videoBitrate = 2500000;
- }
- else if (string.Equals(profile, "internet480", StringComparison.OrdinalIgnoreCase))
- {
- width = 848;
- height = 480;
- isInterlaced = false;
- videoCodec = "h264";
- videoBitrate = 2000000;
- }
- else if (string.Equals(profile, "internet360", StringComparison.OrdinalIgnoreCase))
- {
- width = 640;
- height = 360;
- isInterlaced = false;
- videoCodec = "h264";
- videoBitrate = 1500000;
- }
- else if (string.Equals(profile, "internet240", StringComparison.OrdinalIgnoreCase))
- {
- width = 432;
- height = 240;
- isInterlaced = false;
- videoCodec = "h264";
- videoBitrate = 1000000;
- }
-
- var channels = await GetChannels(info, true, CancellationToken.None).ConfigureAwait(false);
- var channel = channels.FirstOrDefault(i => string.Equals(i.Number, channelId, StringComparison.OrdinalIgnoreCase));
- if (channel != null)
- {
- if (string.IsNullOrWhiteSpace(videoCodec))
- {
- videoCodec = channel.VideoCodec;
- }
- audioCodec = channel.AudioCodec;
-
- if (!videoBitrate.HasValue)
- {
- videoBitrate = (channel.IsHD ?? true) ? 15000000 : 2000000;
- }
- audioBitrate = (channel.IsHD ?? true) ? 448000 : 192000;
- }
-
- // normalize
- if (string.Equals(videoCodec, "mpeg2", StringComparison.OrdinalIgnoreCase))
- {
- videoCodec = "mpeg2video";
- }
-
- string nal = null;
- if (string.Equals(videoCodec, "h264", StringComparison.OrdinalIgnoreCase))
- {
- nal = "0";
- }
-
- var url = GetApiUrl(info, true) + "/auto/v" + channelId;
-
- if (!string.IsNullOrWhiteSpace(profile) && !string.Equals(profile, "native", StringComparison.OrdinalIgnoreCase))
- {
- url += "?transcode=" + profile;
- }
-
- var id = profile;
- if (string.IsNullOrWhiteSpace(id))
- {
- id = "native";
- }
- id += "_" + url.GetMD5().ToString("N");
-
- var mediaSource = new MediaSourceInfo
- {
- Path = url,
- Protocol = MediaProtocol.Http,
- MediaStreams = new List<MediaStream>
- {
- new MediaStream
- {
- Type = MediaStreamType.Video,
- // Set the index to -1 because we don't know the exact index of the video stream within the container
- Index = -1,
- IsInterlaced = isInterlaced,
- Codec = videoCodec,
- Width = width,
- Height = height,
- BitRate = videoBitrate,
- NalLengthSize = nal
-
- },
- new MediaStream
- {
- Type = MediaStreamType.Audio,
- // Set the index to -1 because we don't know the exact index of the audio stream within the container
- Index = -1,
- Codec = audioCodec,
- BitRate = audioBitrate
- }
- },
- RequiresOpening = true,
- RequiresClosing = false,
- BufferMs = 0,
- Container = "ts",
- Id = id,
- SupportsDirectPlay = false,
- SupportsDirectStream = true,
- SupportsTranscoding = true,
- IsInfiniteStream = true
- };
-
- return mediaSource;
- }
-
- protected EncodingOptions GetEncodingOptions()
- {
- return Config.GetConfiguration<EncodingOptions>("encoding");
- }
-
- private string GetHdHrIdFromChannelId(string channelId)
- {
- return channelId.Split('_')[1];
- }
-
- protected override async Task<List<MediaSourceInfo>> GetChannelStreamMediaSources(TunerHostInfo info, string channelId, CancellationToken cancellationToken)
- {
- var list = new List<MediaSourceInfo>();
-
- if (!channelId.StartsWith(ChannelIdPrefix, StringComparison.OrdinalIgnoreCase))
- {
- return list;
- }
- var hdhrId = GetHdHrIdFromChannelId(channelId);
-
- list.Add(await GetMediaSource(info, hdhrId, "native").ConfigureAwait(false));
-
- try
- {
- if (info.AllowHWTranscoding)
- {
- string model = await GetModelInfo(info, cancellationToken).ConfigureAwait(false);
- model = model ?? string.Empty;
-
- if ((model.IndexOf("hdtc", StringComparison.OrdinalIgnoreCase) != -1))
- {
- list.Add(await GetMediaSource(info, hdhrId, "heavy").ConfigureAwait(false));
-
- list.Add(await GetMediaSource(info, hdhrId, "internet540").ConfigureAwait(false));
- list.Add(await GetMediaSource(info, hdhrId, "internet480").ConfigureAwait(false));
- list.Add(await GetMediaSource(info, hdhrId, "internet360").ConfigureAwait(false));
- list.Add(await GetMediaSource(info, hdhrId, "internet240").ConfigureAwait(false));
- list.Add(await GetMediaSource(info, hdhrId, "mobile").ConfigureAwait(false));
- }
- }
- }
- catch
- {
-
- }
-
- return list;
- }
-
- protected override bool IsValidChannelId(string channelId)
- {
- if (string.IsNullOrWhiteSpace(channelId))
- {
- throw new ArgumentNullException("channelId");
- }
-
- return channelId.StartsWith(ChannelIdPrefix, StringComparison.OrdinalIgnoreCase);
- }
-
- protected override async Task<LiveStream> GetChannelStream(TunerHostInfo info, string channelId, string streamId, CancellationToken cancellationToken)
- {
- var profile = streamId.Split('_')[0];
-
- Logger.Info("GetChannelStream: channel id: {0}. stream id: {1} profile: {2}", channelId, streamId, profile);
-
- if (!channelId.StartsWith(ChannelIdPrefix, StringComparison.OrdinalIgnoreCase))
- {
- throw new ArgumentException("Channel not found");
- }
- var hdhrId = GetHdHrIdFromChannelId(channelId);
-
- var mediaSource = await GetMediaSource(info, hdhrId, profile).ConfigureAwait(false);
-
- var liveStream = new HdHomerunLiveStream(mediaSource, streamId, _fileSystem, _httpClient, Logger, Config.ApplicationPaths, _appHost);
- liveStream.EnableStreamSharing = true;
- return liveStream;
- }
-
- public async Task Validate(TunerHostInfo info)
- {
- if (!info.IsEnabled)
- {
- return;
- }
-
- lock (_modelCache)
- {
- _modelCache.Clear();
- }
-
- try
- {
- // Test it by pulling down the lineup
- using (var stream = await _httpClient.Get(new HttpRequestOptions
- {
- Url = string.Format("{0}/discover.json", GetApiUrl(info, false)),
- CancellationToken = CancellationToken.None,
- BufferContent = false
- }))
- {
- var response = JsonSerializer.DeserializeFromStream<DiscoverResponse>(stream);
-
- info.DeviceId = response.DeviceID;
- }
- }
- catch (HttpException ex)
- {
- if (ex.StatusCode.HasValue && ex.StatusCode.Value == System.Net.HttpStatusCode.NotFound)
- {
- // HDHR4 doesn't have this api
- return;
- }
-
- throw;
- }
- }
-
- protected override async Task<bool> IsAvailableInternal(TunerHostInfo tuner, string channelId, CancellationToken cancellationToken)
- {
- var info = await GetTunerInfos(tuner, cancellationToken).ConfigureAwait(false);
-
- return info.Any(i => i.Status == LiveTvTunerStatus.Available);
- }
-
- 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; }
- }
- }
-}
diff --git a/MediaBrowser.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunLiveStream.cs b/MediaBrowser.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunLiveStream.cs
deleted file mode 100644
index 7bb4dc92e0..0000000000
--- a/MediaBrowser.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunLiveStream.cs
+++ /dev/null
@@ -1,147 +0,0 @@
-using System;
-using System.IO;
-using System.Threading;
-using System.Threading.Tasks;
-using MediaBrowser.Model.IO;
-using MediaBrowser.Common.Net;
-using MediaBrowser.Controller;
-using MediaBrowser.Controller.LiveTv;
-using MediaBrowser.Controller.Library;
-using MediaBrowser.Model.Dto;
-using MediaBrowser.Model.Logging;
-using MediaBrowser.Model.MediaInfo;
-using MediaBrowser.Server.Implementations.LiveTv.EmbyTV;
-using System.Collections.Generic;
-using System.Linq;
-using MediaBrowser.Common.Extensions;
-using MediaBrowser.Common.IO;
-using MediaBrowser.Controller.IO;
-
-namespace MediaBrowser.Server.Implementations.LiveTv.TunerHosts.HdHomerun
-{
- public class HdHomerunLiveStream : LiveStream, IDirectStreamProvider
- {
- private readonly ILogger _logger;
- private readonly IHttpClient _httpClient;
- private readonly IFileSystem _fileSystem;
- private readonly IServerApplicationPaths _appPaths;
- private readonly IServerApplicationHost _appHost;
-
- private readonly CancellationTokenSource _liveStreamCancellationTokenSource = new CancellationTokenSource();
- private readonly TaskCompletionSource<bool> _liveStreamTaskCompletionSource = new TaskCompletionSource<bool>();
- private readonly MulticastStream _multicastStream;
-
-
- public HdHomerunLiveStream(MediaSourceInfo mediaSource, string originalStreamId, IFileSystem fileSystem, IHttpClient httpClient, ILogger logger, IServerApplicationPaths appPaths, IServerApplicationHost appHost)
- : base(mediaSource)
- {
- _fileSystem = fileSystem;
- _httpClient = httpClient;
- _logger = logger;
- _appPaths = appPaths;
- _appHost = appHost;
- OriginalStreamId = originalStreamId;
- _multicastStream = new MulticastStream(_logger);
- }
-
- protected override async Task OpenInternal(CancellationToken openCancellationToken)
- {
- _liveStreamCancellationTokenSource.Token.ThrowIfCancellationRequested();
-
- var mediaSource = OriginalMediaSource;
-
- var url = mediaSource.Path;
-
- _logger.Info("Opening HDHR Live stream from {0}", url);
-
- var taskCompletionSource = new TaskCompletionSource<bool>();
-
- StartStreaming(url, taskCompletionSource, _liveStreamCancellationTokenSource.Token);
-
- //OpenedMediaSource.Protocol = MediaProtocol.File;
- //OpenedMediaSource.Path = tempFile;
- //OpenedMediaSource.ReadAtNativeFramerate = true;
-
- OpenedMediaSource.Path = _appHost.GetLocalApiUrl("127.0.0.1") + "/LiveTv/LiveStreamFiles/" + UniqueId + "/stream.ts";
- OpenedMediaSource.Protocol = MediaProtocol.Http;
- OpenedMediaSource.SupportsDirectPlay = false;
- OpenedMediaSource.SupportsDirectStream = true;
- OpenedMediaSource.SupportsTranscoding = true;
-
- await taskCompletionSource.Task.ConfigureAwait(false);
-
- //await Task.Delay(5000).ConfigureAwait(false);
- }
-
- public override Task Close()
- {
- _logger.Info("Closing HDHR live stream");
- _liveStreamCancellationTokenSource.Cancel();
-
- return _liveStreamTaskCompletionSource.Task;
- }
-
- private async Task StartStreaming(string url, TaskCompletionSource<bool> openTaskCompletionSource, CancellationToken cancellationToken)
- {
- await Task.Run(async () =>
- {
- var isFirstAttempt = true;
-
- while (!cancellationToken.IsCancellationRequested)
- {
- try
- {
- using (var response = await _httpClient.SendAsync(new HttpRequestOptions
- {
- Url = url,
- CancellationToken = cancellationToken,
- BufferContent = false
-
- }, "GET").ConfigureAwait(false))
- {
- _logger.Info("Opened HDHR stream from {0}", url);
-
- if (!cancellationToken.IsCancellationRequested)
- {
- _logger.Info("Beginning multicastStream.CopyUntilCancelled");
-
- Action onStarted = null;
- if (isFirstAttempt)
- {
- onStarted = () => openTaskCompletionSource.TrySetResult(true);
- }
-
- await _multicastStream.CopyUntilCancelled(response.Content, onStarted, cancellationToken).ConfigureAwait(false);
- }
- }
- }
- catch (OperationCanceledException)
- {
- break;
- }
- catch (Exception ex)
- {
- if (isFirstAttempt)
- {
- _logger.ErrorException("Error opening live stream:", ex);
- openTaskCompletionSource.TrySetException(ex);
- break;
- }
-
- _logger.ErrorException("Error copying live stream, will reopen", ex);
- }
-
- isFirstAttempt = false;
- }
-
- _liveStreamTaskCompletionSource.TrySetResult(true);
-
- }).ConfigureAwait(false);
- }
-
- public Task CopyToAsync(Stream stream, CancellationToken cancellationToken)
- {
- return _multicastStream.CopyToAsync(stream);
- }
- }
-}
diff --git a/MediaBrowser.Server.Implementations/LiveTv/TunerHosts/M3UTunerHost.cs b/MediaBrowser.Server.Implementations/LiveTv/TunerHosts/M3UTunerHost.cs
deleted file mode 100644
index b85b3810a3..0000000000
--- a/MediaBrowser.Server.Implementations/LiveTv/TunerHosts/M3UTunerHost.cs
+++ /dev/null
@@ -1,167 +0,0 @@
-using MediaBrowser.Common.Configuration;
-using MediaBrowser.Common.Extensions;
-using MediaBrowser.Controller.LiveTv;
-using MediaBrowser.Model.Dto;
-using MediaBrowser.Model.Entities;
-using MediaBrowser.Model.LiveTv;
-using MediaBrowser.Model.Logging;
-using MediaBrowser.Model.MediaInfo;
-using System;
-using System.Collections.Generic;
-using System.Linq;
-using System.Threading;
-using System.Threading.Tasks;
-using MediaBrowser.Common.IO;
-using MediaBrowser.Model.IO;
-using MediaBrowser.Common.Net;
-using MediaBrowser.Controller;
-using MediaBrowser.Controller.Configuration;
-using MediaBrowser.Controller.IO;
-using MediaBrowser.Controller.MediaEncoding;
-using MediaBrowser.Model.Serialization;
-using MediaBrowser.Server.Implementations.LiveTv.EmbyTV;
-
-namespace MediaBrowser.Server.Implementations.LiveTv.TunerHosts
-{
- public class M3UTunerHost : BaseTunerHost, ITunerHost, IConfigurableTunerHost
- {
- private readonly IFileSystem _fileSystem;
- private readonly IHttpClient _httpClient;
- private readonly IServerApplicationHost _appHost;
-
- public M3UTunerHost(IServerConfigurationManager config, ILogger logger, IJsonSerializer jsonSerializer, IMediaEncoder mediaEncoder, IFileSystem fileSystem, IHttpClient httpClient, IServerApplicationHost appHost)
- : base(config, logger, jsonSerializer, mediaEncoder)
- {
- _fileSystem = fileSystem;
- _httpClient = httpClient;
- _appHost = appHost;
- }
-
- public override string Type
- {
- get { return "m3u"; }
- }
-
- public string Name
- {
- get { return "M3U Tuner"; }
- }
-
- private const string ChannelIdPrefix = "m3u_";
-
- protected override async Task<IEnumerable<ChannelInfo>> GetChannelsInternal(TunerHostInfo info, CancellationToken cancellationToken)
- {
- return await new M3uParser(Logger, _fileSystem, _httpClient, _appHost).Parse(info.Url, ChannelIdPrefix, info.Id, cancellationToken).ConfigureAwait(false);
- }
-
- public Task<List<LiveTvTunerInfo>> GetTunerInfos(CancellationToken cancellationToken)
- {
- var list = GetTunerHosts()
- .Select(i => new LiveTvTunerInfo()
- {
- Name = Name,
- SourceType = Type,
- Status = LiveTvTunerStatus.Available,
- Id = i.Url.GetMD5().ToString("N"),
- Url = i.Url
- })
- .ToList();
-
- return Task.FromResult(list);
- }
-
- protected override async Task<LiveStream> GetChannelStream(TunerHostInfo info, string channelId, string streamId, CancellationToken cancellationToken)
- {
- var sources = await GetChannelStreamMediaSources(info, channelId, cancellationToken).ConfigureAwait(false);
-
- var liveStream = new LiveStream(sources.First());
- return liveStream;
- }
-
- public async Task Validate(TunerHostInfo info)
- {
- using (var stream = await new M3uParser(Logger, _fileSystem, _httpClient, _appHost).GetListingsStream(info.Url, CancellationToken.None).ConfigureAwait(false))
- {
-
- }
- }
-
- protected override bool IsValidChannelId(string channelId)
- {
- return channelId.StartsWith(ChannelIdPrefix, StringComparison.OrdinalIgnoreCase);
- }
-
- protected override async Task<List<MediaSourceInfo>> GetChannelStreamMediaSources(TunerHostInfo info, string channelId, CancellationToken cancellationToken)
- {
- var urlHash = info.Url.GetMD5().ToString("N");
- var prefix = ChannelIdPrefix + urlHash;
- if (!channelId.StartsWith(prefix, StringComparison.OrdinalIgnoreCase))
- {
- return null;
- }
-
- var channels = await GetChannels(info, true, cancellationToken).ConfigureAwait(false);
- var m3uchannels = channels.Cast<M3UChannel>();
- var channel = m3uchannels.FirstOrDefault(c => string.Equals(c.Id, channelId, StringComparison.OrdinalIgnoreCase));
- if (channel != null)
- {
- var path = channel.Path;
- MediaProtocol protocol = MediaProtocol.File;
- if (path.StartsWith("http", StringComparison.OrdinalIgnoreCase))
- {
- protocol = MediaProtocol.Http;
- }
- else if (path.StartsWith("rtmp", StringComparison.OrdinalIgnoreCase))
- {
- protocol = MediaProtocol.Rtmp;
- }
- else if (path.StartsWith("rtsp", StringComparison.OrdinalIgnoreCase))
- {
- protocol = MediaProtocol.Rtsp;
- }
- else if (path.StartsWith("udp", StringComparison.OrdinalIgnoreCase))
- {
- protocol = MediaProtocol.Udp;
- }
-
- var mediaSource = new MediaSourceInfo
- {
- Path = channel.Path,
- Protocol = protocol,
- MediaStreams = new List<MediaStream>
- {
- new MediaStream
- {
- Type = MediaStreamType.Video,
- // Set the index to -1 because we don't know the exact index of the video stream within the container
- Index = -1,
- IsInterlaced = true
- },
- new MediaStream
- {
- Type = MediaStreamType.Audio,
- // Set the index to -1 because we don't know the exact index of the audio stream within the container
- Index = -1
-
- }
- },
- RequiresOpening = false,
- RequiresClosing = false,
-
- ReadAtNativeFramerate = false,
-
- Id = channel.Path.GetMD5().ToString("N"),
- IsInfiniteStream = true
- };
-
- return new List<MediaSourceInfo> { mediaSource };
- }
- return new List<MediaSourceInfo>();
- }
-
- protected override Task<bool> IsAvailableInternal(TunerHostInfo tuner, string channelId, CancellationToken cancellationToken)
- {
- return Task.FromResult(true);
- }
- }
-}
diff --git a/MediaBrowser.Server.Implementations/LiveTv/TunerHosts/M3uParser.cs b/MediaBrowser.Server.Implementations/LiveTv/TunerHosts/M3uParser.cs
deleted file mode 100644
index 3bfe902dfb..0000000000
--- a/MediaBrowser.Server.Implementations/LiveTv/TunerHosts/M3uParser.cs
+++ /dev/null
@@ -1,169 +0,0 @@
-using System;
-using System.Collections.Generic;
-using System.IO;
-using System.Linq;
-using System.Text.RegularExpressions;
-using System.Threading;
-using System.Threading.Tasks;
-using MediaBrowser.Model.IO;
-using MediaBrowser.Common.Extensions;
-using MediaBrowser.Common.IO;
-using MediaBrowser.Common.Net;
-using MediaBrowser.Controller;
-using MediaBrowser.Controller.IO;
-using MediaBrowser.Controller.LiveTv;
-using MediaBrowser.Model.Logging;
-
-namespace MediaBrowser.Server.Implementations.LiveTv.TunerHosts
-{
- public class M3uParser
- {
- private readonly ILogger _logger;
- private readonly IFileSystem _fileSystem;
- private readonly IHttpClient _httpClient;
- private readonly IServerApplicationHost _appHost;
-
- public M3uParser(ILogger logger, IFileSystem fileSystem, IHttpClient httpClient, IServerApplicationHost appHost)
- {
- _logger = logger;
- _fileSystem = fileSystem;
- _httpClient = httpClient;
- _appHost = appHost;
- }
-
- public async Task<List<M3UChannel>> Parse(string url, string channelIdPrefix, string tunerHostId, CancellationToken cancellationToken)
- {
- var urlHash = url.GetMD5().ToString("N");
-
- // Read the file and display it line by line.
- using (var reader = new StreamReader(await GetListingsStream(url, cancellationToken).ConfigureAwait(false)))
- {
- return GetChannels(reader, urlHash, channelIdPrefix, tunerHostId);
- }
- }
-
- public Task<Stream> GetListingsStream(string url, CancellationToken cancellationToken)
- {
- 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.FriendlyName + "/" + _appHost.ApplicationVersion
- });
- }
- return Task.FromResult(_fileSystem.OpenRead(url));
- }
-
- private List<M3UChannel> GetChannels(StreamReader reader, string urlHash, string channelIdPrefix, string tunerHostId)
- {
- var channels = new List<M3UChannel>();
- string line;
- string extInf = "";
- while ((line = reader.ReadLine()) != null)
- {
- line = line.Trim();
- if (string.IsNullOrWhiteSpace(line))
- {
- continue;
- }
-
- if (line.StartsWith("#EXTM3U", StringComparison.OrdinalIgnoreCase))
- {
- continue;
- }
-
- if (line.StartsWith("#EXTINF:", StringComparison.OrdinalIgnoreCase))
- {
- extInf = line.Substring(8).Trim();
- _logger.Info("Found m3u channel: {0}", extInf);
- }
- else if (!string.IsNullOrWhiteSpace(extInf) && !line.StartsWith("#", StringComparison.OrdinalIgnoreCase))
- {
- var channel = GetChannelnfo(extInf, tunerHostId, line);
- channel.Id = channelIdPrefix + urlHash + line.GetMD5().ToString("N");
- channel.Path = line;
- channels.Add(channel);
- extInf = "";
- }
- }
- return channels;
- }
- private M3UChannel GetChannelnfo(string extInf, string tunerHostId, string mediaUrl)
- {
- var titleIndex = extInf.LastIndexOf(',');
- var channel = new M3UChannel();
- channel.TunerHostId = tunerHostId;
-
- channel.Number = extInf.Trim().Split(' ')[0] ?? "0";
- channel.Name = extInf.Substring(titleIndex + 1);
-
- //Check for channel number with the format from SatIp
- int number;
- var numberIndex = channel.Name.IndexOf('.');
- if (numberIndex > 0)
- {
- if (int.TryParse(channel.Name.Substring(0, numberIndex), out number))
- {
- channel.Number = number.ToString();
- channel.Name = channel.Name.Substring(numberIndex + 1);
- }
- }
-
- if (string.Equals(channel.Number, "-1", StringComparison.OrdinalIgnoreCase) && !string.IsNullOrWhiteSpace(mediaUrl))
- {
- channel.Number = Path.GetFileNameWithoutExtension(mediaUrl.Split('/').Last());
- }
-
- if (string.Equals(channel.Number, "-1", StringComparison.OrdinalIgnoreCase))
- {
- channel.Number = "0";
- }
-
- channel.ImageUrl = FindProperty("tvg-logo", extInf);
-
- var name = FindProperty("tvg-name", extInf);
- if (string.IsNullOrWhiteSpace(name))
- {
- name = FindProperty("tvg-id", extInf);
- }
-
- channel.Name = name;
-
- var numberString = FindProperty("tvg-id", extInf);
- if (string.IsNullOrWhiteSpace(numberString))
- {
- numberString = FindProperty("channel-id", extInf);
- }
-
- if (!string.IsNullOrWhiteSpace(numberString))
- {
- channel.Number = numberString;
- }
-
- return channel;
-
- }
- private string FindProperty(string property, string properties)
- {
- var reg = new Regex(@"([a-z0-9\-_]+)=\""([^""]+)\""", RegexOptions.IgnoreCase);
- var matches = reg.Matches(properties);
- foreach (Match match in matches)
- {
- if (match.Groups[1].Value == property)
- {
- return match.Groups[2].Value;
- }
- }
- return null;
- }
- }
-
-
- public class M3UChannel : ChannelInfo
- {
- public string Path { get; set; }
- }
-} \ No newline at end of file
diff --git a/MediaBrowser.Server.Implementations/LiveTv/TunerHosts/MulticastStream.cs b/MediaBrowser.Server.Implementations/LiveTv/TunerHosts/MulticastStream.cs
deleted file mode 100644
index 8ff3fd6c17..0000000000
--- a/MediaBrowser.Server.Implementations/LiveTv/TunerHosts/MulticastStream.cs
+++ /dev/null
@@ -1,96 +0,0 @@
-using System;
-using System.Collections.Generic;
-using System.IO;
-using System.Linq;
-using System.Text;
-using System.Threading;
-using System.Threading.Tasks;
-using MediaBrowser.Model.Logging;
-
-namespace MediaBrowser.Server.Implementations.LiveTv.TunerHosts
-{
- public class MulticastStream
- {
- private readonly List<QueueStream> _outputStreams = new List<QueueStream>();
- private const int BufferSize = 81920;
- private CancellationToken _cancellationToken;
- private readonly ILogger _logger;
-
- public MulticastStream(ILogger logger)
- {
- _logger = logger;
- }
-
- public async Task CopyUntilCancelled(Stream source, Action onStarted, CancellationToken cancellationToken)
- {
- _cancellationToken = cancellationToken;
-
- while (!cancellationToken.IsCancellationRequested)
- {
- byte[] buffer = new byte[BufferSize];
-
- var bytesRead = await source.ReadAsync(buffer, 0, buffer.Length, cancellationToken).ConfigureAwait(false);
-
- if (bytesRead > 0)
- {
- byte[] copy = new byte[bytesRead];
- Buffer.BlockCopy(buffer, 0, copy, 0, bytesRead);
-
- List<QueueStream> streams = null;
-
- lock (_outputStreams)
- {
- streams = _outputStreams.ToList();
- }
-
- foreach (var stream in streams)
- {
- stream.Queue(copy);
- }
-
- if (onStarted != null)
- {
- var onStartedCopy = onStarted;
- onStarted = null;
- Task.Run(onStartedCopy);
- }
- }
-
- else
- {
- await Task.Delay(100).ConfigureAwait(false);
- }
- }
- }
-
- public Task CopyToAsync(Stream stream)
- {
- var result = new QueueStream(stream, _logger)
- {
- OnFinished = OnFinished
- };
-
- lock (_outputStreams)
- {
- _outputStreams.Add(result);
- }
-
- result.Start(_cancellationToken);
-
- return result.TaskCompletion.Task;
- }
-
- public void RemoveOutputStream(QueueStream stream)
- {
- lock (_outputStreams)
- {
- _outputStreams.Remove(stream);
- }
- }
-
- private void OnFinished(QueueStream queueStream)
- {
- RemoveOutputStream(queueStream);
- }
- }
-}
diff --git a/MediaBrowser.Server.Implementations/LiveTv/TunerHosts/QueueStream.cs b/MediaBrowser.Server.Implementations/LiveTv/TunerHosts/QueueStream.cs
deleted file mode 100644
index c1566b9006..0000000000
--- a/MediaBrowser.Server.Implementations/LiveTv/TunerHosts/QueueStream.cs
+++ /dev/null
@@ -1,93 +0,0 @@
-using System;
-using System.Collections.Concurrent;
-using System.Collections.Generic;
-using System.IO;
-using System.Linq;
-using System.Text;
-using System.Threading;
-using System.Threading.Tasks;
-using MediaBrowser.Model.Logging;
-
-namespace MediaBrowser.Server.Implementations.LiveTv.TunerHosts
-{
- public class QueueStream
- {
- private readonly Stream _outputStream;
- private readonly ConcurrentQueue<byte[]> _queue = new ConcurrentQueue<byte[]>();
- private CancellationToken _cancellationToken;
- public TaskCompletionSource<bool> TaskCompletion { get; private set; }
-
- public Action<QueueStream> OnFinished { get; set; }
- private readonly ILogger _logger;
-
- public QueueStream(Stream outputStream, ILogger logger)
- {
- _outputStream = outputStream;
- _logger = logger;
- TaskCompletion = new TaskCompletionSource<bool>();
- }
-
- public void Queue(byte[] bytes)
- {
- _queue.Enqueue(bytes);
- }
-
- public void Start(CancellationToken cancellationToken)
- {
- _cancellationToken = cancellationToken;
- Task.Run(() => StartInternal());
- }
-
- private byte[] Dequeue()
- {
- byte[] bytes;
- if (_queue.TryDequeue(out bytes))
- {
- return bytes;
- }
-
- return null;
- }
-
- private async Task StartInternal()
- {
- var cancellationToken = _cancellationToken;
-
- try
- {
- while (!cancellationToken.IsCancellationRequested)
- {
- var bytes = Dequeue();
- if (bytes != null)
- {
- await _outputStream.WriteAsync(bytes, 0, bytes.Length, cancellationToken).ConfigureAwait(false);
- }
- else
- {
- await Task.Delay(50, cancellationToken).ConfigureAwait(false);
- }
- }
-
- TaskCompletion.TrySetResult(true);
- _logger.Debug("QueueStream complete");
- }
- catch (OperationCanceledException)
- {
- _logger.Debug("QueueStream cancelled");
- TaskCompletion.TrySetCanceled();
- }
- catch (Exception ex)
- {
- _logger.ErrorException("Error in QueueStream", ex);
- TaskCompletion.TrySetException(ex);
- }
- finally
- {
- if (OnFinished != null)
- {
- OnFinished(this);
- }
- }
- }
- }
-}
diff --git a/MediaBrowser.Server.Implementations/LiveTv/TunerHosts/SatIp/SatIpHost.cs b/MediaBrowser.Server.Implementations/LiveTv/TunerHosts/SatIp/SatIpHost.cs
index 8dca261a38..55101ce10f 100644
--- a/MediaBrowser.Server.Implementations/LiveTv/TunerHosts/SatIp/SatIpHost.cs
+++ b/MediaBrowser.Server.Implementations/LiveTv/TunerHosts/SatIp/SatIpHost.cs
@@ -4,6 +4,7 @@ using System.Globalization;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
+using Emby.Server.Implementations.LiveTv.TunerHosts;
using MediaBrowser.Model.IO;
using MediaBrowser.Common.Configuration;
using MediaBrowser.Common.Extensions;
@@ -20,7 +21,6 @@ using MediaBrowser.Model.LiveTv;
using MediaBrowser.Model.Logging;
using MediaBrowser.Model.MediaInfo;
using MediaBrowser.Model.Serialization;
-using MediaBrowser.Server.Implementations.LiveTv.EmbyTV;
namespace MediaBrowser.Server.Implementations.LiveTv.TunerHosts.SatIp
{