diff --git a/MediaBrowser.Api/ConnectService.cs b/MediaBrowser.Api/ConnectService.cs index bdd2eeaadd..4bcd33d9e3 100644 --- a/MediaBrowser.Api/ConnectService.cs +++ b/MediaBrowser.Api/ConnectService.cs @@ -1,10 +1,8 @@ -using System; -using MediaBrowser.Common.Extensions; +using MediaBrowser.Common.Extensions; using MediaBrowser.Controller.Connect; using MediaBrowser.Controller.Library; using MediaBrowser.Controller.Net; using MediaBrowser.Model.Connect; -using MediaBrowser.Model.Dto; using ServiceStack; using System.Collections.Generic; using System.Linq; @@ -75,28 +73,6 @@ namespace MediaBrowser.Api public string ConnectUserId { get; set; } } - [Route("/Connect/Supporters", "GET")] - [Authenticated(Roles = "Admin")] - public class GetConnectSupporterSummary : IReturn - { - } - - [Route("/Connect/Supporters", "DELETE")] - [Authenticated(Roles = "Admin")] - public class RemoveConnectSupporter : IReturnVoid - { - [ApiMember(Name = "Id", Description = "User Id", IsRequired = true, DataType = "string", ParameterType = "query", Verb = "DELETE")] - public string Id { get; set; } - } - - [Route("/Connect/Supporters", "POST")] - [Authenticated(Roles = "Admin")] - public class AddConnectSupporter : IReturnVoid - { - [ApiMember(Name = "Id", Description = "User Id", IsRequired = true, DataType = "string", ParameterType = "query", Verb = "POST")] - public string Id { get; set; } - } - public class ConnectService : BaseApiService { private readonly IConnectManager _connectManager; @@ -108,35 +84,6 @@ namespace MediaBrowser.Api _userManager = userManager; } - public async Task Get(GetConnectSupporterSummary request) - { - var result = await _connectManager.GetConnectSupporterSummary().ConfigureAwait(false); - var existingConnectUserIds = result.Users.Select(i => i.Id).ToList(); - - result.EligibleUsers = _userManager.Users - .Where(i => !string.IsNullOrWhiteSpace(i.ConnectUserId)) - .Where(i => !existingConnectUserIds.Contains(i.ConnectUserId, StringComparer.OrdinalIgnoreCase)) - .OrderBy(i => i.Name) - .Select(i => _userManager.GetUserDto(i)) - .ToList(); - - return ToOptimizedResult(result); - } - - public void Delete(RemoveConnectSupporter request) - { - var task = _connectManager.RemoveConnectSupporter(request.Id); - - Task.WaitAll(task); - } - - public void Post(AddConnectSupporter request) - { - var task = _connectManager.AddConnectSupporter(request.Id); - - Task.WaitAll(task); - } - public object Post(CreateConnectLink request) { return _connectManager.LinkUser(request.Id, request.ConnectUsername); diff --git a/MediaBrowser.Controller/Connect/IConnectManager.cs b/MediaBrowser.Controller/Connect/IConnectManager.cs index 1f76522214..e004eaccfa 100644 --- a/MediaBrowser.Controller/Connect/IConnectManager.cs +++ b/MediaBrowser.Controller/Connect/IConnectManager.cs @@ -76,25 +76,5 @@ namespace MediaBrowser.Controller.Connect /// The token. /// true if [is authorization token valid] [the specified token]; otherwise, false. bool IsAuthorizationTokenValid(string token); - - /// - /// Gets the connect supporter summary. - /// - /// Task<ConnectSupporterSummary>. - Task GetConnectSupporterSummary(); - - /// - /// Removes the connect supporter. - /// - /// The identifier. - /// Task. - Task RemoveConnectSupporter(string id); - - /// - /// Adds the connect supporter. - /// - /// The identifier. - /// Task. - Task AddConnectSupporter(string id); } } diff --git a/MediaBrowser.Controller/LiveTv/ITunerHost.cs b/MediaBrowser.Controller/LiveTv/ITunerHost.cs index 2e3a71f703..498602ddf9 100644 --- a/MediaBrowser.Controller/LiveTv/ITunerHost.cs +++ b/MediaBrowser.Controller/LiveTv/ITunerHost.cs @@ -46,6 +46,9 @@ namespace MediaBrowser.Controller.LiveTv /// The cancellation token. /// Task<List<MediaSourceInfo>>. Task> GetChannelStreamMediaSources(string channelId, CancellationToken cancellationToken); + } + public interface IConfigurableTunerHost + { /// /// Validates the specified information. /// diff --git a/MediaBrowser.Model/Configuration/ServerConfiguration.cs b/MediaBrowser.Model/Configuration/ServerConfiguration.cs index 3cb543e5d5..bc102bd40a 100644 --- a/MediaBrowser.Model/Configuration/ServerConfiguration.cs +++ b/MediaBrowser.Model/Configuration/ServerConfiguration.cs @@ -182,8 +182,6 @@ namespace MediaBrowser.Model.Configuration public PeopleMetadataOptions PeopleMetadataOptions { get; set; } public bool FindInternetTrailers { get; set; } - public string[] InsecureApps9 { get; set; } - public bool SaveMetadataHidden { get; set; } public NameValuePair[] ContentTypes { get; set; } @@ -256,11 +254,6 @@ namespace MediaBrowser.Model.Configuration PeopleMetadataOptions = new PeopleMetadataOptions(); - InsecureApps9 = new[] - { - "Windows Phone" - }; - MetadataOptions = new[] { new MetadataOptions(1, 1280) {ItemType = "Book"}, diff --git a/MediaBrowser.Server.Implementations/Connect/ConnectManager.cs b/MediaBrowser.Server.Implementations/Connect/ConnectManager.cs index fdc7e9ee27..d7477225c8 100644 --- a/MediaBrowser.Server.Implementations/Connect/ConnectManager.cs +++ b/MediaBrowser.Server.Implementations/Connect/ConnectManager.cs @@ -10,7 +10,6 @@ using MediaBrowser.Controller.Providers; using MediaBrowser.Controller.Security; using MediaBrowser.Model.Connect; using MediaBrowser.Model.Entities; -using MediaBrowser.Model.Events; using MediaBrowser.Model.Logging; using MediaBrowser.Model.Net; using MediaBrowser.Model.Serialization; @@ -24,7 +23,6 @@ using System.Text; using System.Threading; using System.Threading.Tasks; using CommonIO; -using MediaBrowser.Common.IO; namespace MediaBrowser.Server.Implementations.Connect { @@ -121,7 +119,6 @@ namespace MediaBrowser.Server.Implementations.Connect _securityManager = securityManager; _fileSystem = fileSystem; - _userManager.UserConfigurationUpdated += _userManager_UserConfigurationUpdated; _config.ConfigurationUpdated += _config_ConfigurationUpdated; LoadCachedData(); @@ -1071,90 +1068,6 @@ namespace MediaBrowser.Server.Implementations.Connect } } - public async Task GetConnectSupporterSummary() - { - var url = GetConnectUrl("keyAssociation"); - - var options = new HttpRequestOptions - { - Url = url, - CancellationToken = CancellationToken.None - }; - - var postData = new Dictionary - { - {"serverId", ConnectServerId}, - {"supporterKey", _securityManager.SupporterKey} - }; - - options.SetPostData(postData); - - SetServerAccessToken(options); - SetApplicationHeader(options); - - // No need to examine the response - using (var stream = (await _httpClient.SendAsync(options, "POST").ConfigureAwait(false)).Content) - { - return _json.DeserializeFromStream(stream); - } - } - - public async Task AddConnectSupporter(string id) - { - var url = GetConnectUrl("keyAssociation"); - - var options = new HttpRequestOptions - { - Url = url, - CancellationToken = CancellationToken.None - }; - - var postData = new Dictionary - { - {"serverId", ConnectServerId}, - {"supporterKey", _securityManager.SupporterKey}, - {"userId", id} - }; - - options.SetPostData(postData); - - SetServerAccessToken(options); - SetApplicationHeader(options); - - // No need to examine the response - using (var stream = (await _httpClient.SendAsync(options, "POST").ConfigureAwait(false)).Content) - { - } - } - - public async Task RemoveConnectSupporter(string id) - { - var url = GetConnectUrl("keyAssociation"); - - var options = new HttpRequestOptions - { - Url = url, - CancellationToken = CancellationToken.None - }; - - var postData = new Dictionary - { - {"serverId", ConnectServerId}, - {"supporterKey", _securityManager.SupporterKey}, - {"userId", id} - }; - - options.SetPostData(postData); - - SetServerAccessToken(options); - SetApplicationHeader(options); - - // No need to examine the response - using (var stream = (await _httpClient.SendAsync(options, "DELETE").ConfigureAwait(false)).Content) - { - } - } - public async Task Authenticate(string username, string passwordMd5) { if (string.IsNullOrWhiteSpace(username)) @@ -1186,64 +1099,6 @@ namespace MediaBrowser.Server.Implementations.Connect } } - async void _userManager_UserConfigurationUpdated(object sender, GenericEventArgs e) - { - var user = e.Argument; - - await TryUploadUserPreferences(user, CancellationToken.None).ConfigureAwait(false); - } - - private async Task TryUploadUserPreferences(User user, CancellationToken cancellationToken) - { - if (user == null) - { - throw new ArgumentNullException("user"); - } - - if (string.IsNullOrEmpty(user.ConnectUserId)) - { - return; - } - if (string.IsNullOrEmpty(ConnectAccessKey)) - { - return; - } - - var url = GetConnectUrl("user/preferences"); - url += "?userId=" + user.ConnectUserId; - url += "&key=userpreferences"; - - var options = new HttpRequestOptions - { - Url = url, - CancellationToken = cancellationToken - }; - - var postData = new Dictionary(); - postData["data"] = _json.SerializeToString(ConnectUserPreferences.FromUserConfiguration(user.Configuration)); - options.SetPostData(postData); - - SetServerAccessToken(options); - SetApplicationHeader(options); - - try - { - // No need to examine the response - using (var stream = (await _httpClient.SendAsync(options, "POST").ConfigureAwait(false)).Content) - { - } - } - catch (Exception ex) - { - _logger.ErrorException("Error uploading user preferences", ex); - } - } - - private async Task DownloadUserPreferences(User user, CancellationToken cancellationToken) - { - - } - public async Task GetLocalUser(string connectUserId) { var user = _userManager.Users diff --git a/MediaBrowser.Server.Implementations/HttpServer/Security/AuthService.cs b/MediaBrowser.Server.Implementations/HttpServer/Security/AuthService.cs index f6b14fcab3..d8f7d889c3 100644 --- a/MediaBrowser.Server.Implementations/HttpServer/Security/AuthService.cs +++ b/MediaBrowser.Server.Implementations/HttpServer/Security/AuthService.cs @@ -134,20 +134,17 @@ namespace MediaBrowser.Server.Implementations.HttpServer.Security private bool IsExemptFromAuthenticationToken(AuthorizationInfo auth, IAuthenticationAttributes authAttribtues) { - if (!_config.Configuration.IsStartupWizardCompleted && - authAttribtues.AllowBeforeStartupWizard) + if (!_config.Configuration.IsStartupWizardCompleted && authAttribtues.AllowBeforeStartupWizard) { return true; } - return _config.Configuration.InsecureApps9.Contains(auth.Client ?? string.Empty, - StringComparer.OrdinalIgnoreCase); + return false; } private bool IsExemptFromRoles(AuthorizationInfo auth, IAuthenticationAttributes authAttribtues, AuthenticationInfo tokenInfo) { - if (!_config.Configuration.IsStartupWizardCompleted && - authAttribtues.AllowBeforeStartupWizard) + if (!_config.Configuration.IsStartupWizardCompleted && authAttribtues.AllowBeforeStartupWizard) { return true; } diff --git a/MediaBrowser.Server.Implementations/HttpServer/Security/AuthorizationContext.cs b/MediaBrowser.Server.Implementations/HttpServer/Security/AuthorizationContext.cs index 75d54a80af..357f5c9769 100644 --- a/MediaBrowser.Server.Implementations/HttpServer/Security/AuthorizationContext.cs +++ b/MediaBrowser.Server.Implementations/HttpServer/Security/AuthorizationContext.cs @@ -45,7 +45,6 @@ namespace MediaBrowser.Server.Implementations.HttpServer.Security { var auth = GetAuthorizationDictionary(httpReq); - string userId = null; string deviceId = null; string device = null; string client = null; @@ -53,9 +52,6 @@ namespace MediaBrowser.Server.Implementations.HttpServer.Security if (auth != null) { - // TODO: Remove this - auth.TryGetValue("UserId", out userId); - auth.TryGetValue("DeviceId", out deviceId); auth.TryGetValue("Device", out device); auth.TryGetValue("Client", out client); @@ -78,7 +74,6 @@ namespace MediaBrowser.Server.Implementations.HttpServer.Security Client = client, Device = device, DeviceId = deviceId, - UserId = userId, Version = version, Token = token }; diff --git a/MediaBrowser.Server.Implementations/LiveTv/LiveTvManager.cs b/MediaBrowser.Server.Implementations/LiveTv/LiveTvManager.cs index 14bfcba27a..7c26f5675a 100644 --- a/MediaBrowser.Server.Implementations/LiveTv/LiveTvManager.cs +++ b/MediaBrowser.Server.Implementations/LiveTv/LiveTvManager.cs @@ -2343,7 +2343,11 @@ namespace MediaBrowser.Server.Implementations.LiveTv throw new ResourceNotFoundException(); } - await provider.Validate(info).ConfigureAwait(false); + var configurable = provider as IConfigurableTunerHost; + if (configurable != null) + { + await configurable.Validate(info).ConfigureAwait(false); + } var config = GetConfiguration(); diff --git a/MediaBrowser.Server.Implementations/LiveTv/TunerHosts/BaseTunerHost.cs b/MediaBrowser.Server.Implementations/LiveTv/TunerHosts/BaseTunerHost.cs index 4ebc173b54..fb27631e5a 100644 --- a/MediaBrowser.Server.Implementations/LiveTv/TunerHosts/BaseTunerHost.cs +++ b/MediaBrowser.Server.Implementations/LiveTv/TunerHosts/BaseTunerHost.cs @@ -64,7 +64,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv.TunerHosts return list; } - private List GetTunerHosts() + protected virtual List GetTunerHosts() { return GetConfiguration().TunerHosts .Where(i => i.IsEnabled && string.Equals(i.Type, Type, StringComparison.OrdinalIgnoreCase)) diff --git a/MediaBrowser.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunHost.cs b/MediaBrowser.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunHost.cs index 0671a9b56c..013dabe268 100644 --- a/MediaBrowser.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunHost.cs +++ b/MediaBrowser.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunHost.cs @@ -20,7 +20,7 @@ using MediaBrowser.Model.Dlna; namespace MediaBrowser.Server.Implementations.LiveTv.TunerHosts.HdHomerun { - public class HdHomerunHost : BaseTunerHost, ITunerHost + public class HdHomerunHost : BaseTunerHost, ITunerHost, IConfigurableTunerHost { private readonly IHttpClient _httpClient; diff --git a/MediaBrowser.Server.Implementations/LiveTv/TunerHosts/M3UTunerHost.cs b/MediaBrowser.Server.Implementations/LiveTv/TunerHosts/M3UTunerHost.cs index f87d4f43f5..17e52fb8e7 100644 --- a/MediaBrowser.Server.Implementations/LiveTv/TunerHosts/M3UTunerHost.cs +++ b/MediaBrowser.Server.Implementations/LiveTv/TunerHosts/M3UTunerHost.cs @@ -8,19 +8,17 @@ using MediaBrowser.Model.Logging; using MediaBrowser.Model.MediaInfo; using System; using System.Collections.Generic; -using System.IO; using System.Linq; using System.Threading; using System.Threading.Tasks; using CommonIO; -using MediaBrowser.Common.IO; using MediaBrowser.Common.Net; using MediaBrowser.Controller.MediaEncoding; using MediaBrowser.Model.Serialization; namespace MediaBrowser.Server.Implementations.LiveTv.TunerHosts { - public class M3UTunerHost : BaseTunerHost, ITunerHost + public class M3UTunerHost : BaseTunerHost, ITunerHost, IConfigurableTunerHost { private readonly IFileSystem _fileSystem; private readonly IHttpClient _httpClient; @@ -46,65 +44,12 @@ namespace MediaBrowser.Server.Implementations.LiveTv.TunerHosts protected override async Task> GetChannelsInternal(TunerHostInfo info, CancellationToken cancellationToken) { - var urlHash = info.Url.GetMD5().ToString("N"); - - // Read the file and display it line by line. - using (var reader = new StreamReader(await GetListingsStream(info, cancellationToken).ConfigureAwait(false))) - { - return GetChannels(reader, urlHash); - } - } - - private List GetChannels(StreamReader reader, string urlHash) - { - var channels = new List(); - - string channnelName = null; - string channelNumber = null; - string line; - - 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)) - { - line = line.Substring(8); - Logger.Info("Found m3u channel: {0}", line); - var parts = line.Split(new[] { ',' }, 2); - channelNumber = parts[0]; - channnelName = parts[1]; - } - else if (!string.IsNullOrWhiteSpace(channelNumber)) - { - channels.Add(new M3UChannel - { - Name = channnelName, - Number = channelNumber, - Id = ChannelIdPrefix + urlHash + line.GetMD5().ToString("N"), - Path = line - }); - - channelNumber = null; - channnelName = null; - } - } - return channels; + return await new M3uParser(Logger, _fileSystem, _httpClient).Parse(info.Url, ChannelIdPrefix, cancellationToken).ConfigureAwait(false); } public Task> GetTunerInfos(CancellationToken cancellationToken) { - var list = GetConfiguration().TunerHosts - .Where(i => i.IsEnabled && string.Equals(i.Type, Type, StringComparison.OrdinalIgnoreCase)) + var list = GetTunerHosts() .Select(i => new LiveTvTunerInfo() { Name = Name, @@ -125,18 +70,9 @@ namespace MediaBrowser.Server.Implementations.LiveTv.TunerHosts return sources.First(); } - class M3UChannel : ChannelInfo - { - public string Path { get; set; } - - public M3UChannel() - { - } - } - public async Task Validate(TunerHostInfo info) { - using (var stream = await GetListingsStream(info, CancellationToken.None).ConfigureAwait(false)) + using (var stream = await new M3uParser(Logger, _fileSystem, _httpClient).GetListingsStream(info.Url, CancellationToken.None).ConfigureAwait(false)) { } @@ -147,15 +83,6 @@ namespace MediaBrowser.Server.Implementations.LiveTv.TunerHosts return channelId.StartsWith(ChannelIdPrefix, StringComparison.OrdinalIgnoreCase); } - private Task GetListingsStream(TunerHostInfo info, CancellationToken cancellationToken) - { - if (info.Url.StartsWith("http", StringComparison.OrdinalIgnoreCase)) - { - return _httpClient.Get(info.Url, cancellationToken); - } - return Task.FromResult(_fileSystem.OpenRead(info.Url)); - } - protected override async Task> GetChannelStreamMediaSources(TunerHostInfo info, string channelId, CancellationToken cancellationToken) { var urlHash = info.Url.GetMD5().ToString("N"); diff --git a/MediaBrowser.Server.Implementations/LiveTv/TunerHosts/M3uParser.cs b/MediaBrowser.Server.Implementations/LiveTv/TunerHosts/M3uParser.cs new file mode 100644 index 0000000000..8f5a4a0951 --- /dev/null +++ b/MediaBrowser.Server.Implementations/LiveTv/TunerHosts/M3uParser.cs @@ -0,0 +1,102 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Threading; +using System.Threading.Tasks; +using CommonIO; +using MediaBrowser.Common.Extensions; +using MediaBrowser.Common.Net; +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; + + public M3uParser(ILogger logger, IFileSystem fileSystem, IHttpClient httpClient) + { + _logger = logger; + _fileSystem = fileSystem; + _httpClient = httpClient; + } + + public async Task> Parse(string url, string channelIdPrefix, 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); + } + } + + public Task GetListingsStream(string url, CancellationToken cancellationToken) + { + if (url.StartsWith("http", StringComparison.OrdinalIgnoreCase)) + { + return _httpClient.Get(url, cancellationToken); + } + return Task.FromResult(_fileSystem.OpenRead(url)); + } + + private List GetChannels(StreamReader reader, string urlHash, string channelIdPrefix) + { + var channels = new List(); + + string channnelName = null; + string channelNumber = null; + string line; + + 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)) + { + line = line.Substring(8); + _logger.Info("Found m3u channel: {0}", line); + var parts = line.Split(new[] { ',' }, 2); + channelNumber = parts[0]; + channnelName = parts[1]; + } + else if (!string.IsNullOrWhiteSpace(channelNumber)) + { + channels.Add(new M3UChannel + { + Name = channnelName, + Number = channelNumber, + Id = channelIdPrefix + urlHash + line.GetMD5().ToString("N"), + Path = line + }); + + channelNumber = null; + channnelName = null; + } + } + return channels; + } + } + + public class M3UChannel : ChannelInfo + { + public string Path { get; set; } + + public M3UChannel() + { + } + } +} diff --git a/MediaBrowser.Server.Implementations/LiveTv/TunerHosts/SatIp/SatIpDiscovery.cs b/MediaBrowser.Server.Implementations/LiveTv/TunerHosts/SatIp/SatIpDiscovery.cs index 852b86467c..53f97f76f3 100644 --- a/MediaBrowser.Server.Implementations/LiveTv/TunerHosts/SatIp/SatIpDiscovery.cs +++ b/MediaBrowser.Server.Implementations/LiveTv/TunerHosts/SatIp/SatIpDiscovery.cs @@ -1,10 +1,13 @@ using System; using System.Collections.Generic; +using System.IO; using System.Linq; using System.Text; using System.Threading; using System.Threading.Tasks; +using System.Xml; using MediaBrowser.Common.Configuration; +using MediaBrowser.Common.Extensions; using MediaBrowser.Common.Net; using MediaBrowser.Controller.Configuration; using MediaBrowser.Controller.Dlna; @@ -13,6 +16,7 @@ using MediaBrowser.Controller.Plugins; using MediaBrowser.Model.Extensions; using MediaBrowser.Model.LiveTv; using MediaBrowser.Model.Logging; +using MediaBrowser.Model.Serialization; namespace MediaBrowser.Server.Implementations.LiveTv.TunerHosts.SatIp { @@ -24,14 +28,26 @@ namespace MediaBrowser.Server.Implementations.LiveTv.TunerHosts.SatIp private readonly ILiveTvManager _liveTvManager; private readonly SemaphoreSlim _semaphore = new SemaphoreSlim(1, 1); private readonly IHttpClient _httpClient; + private readonly IJsonSerializer _json; - public SatIpDiscovery(IDeviceDiscovery deviceDiscovery, IServerConfigurationManager config, ILogger logger, ILiveTvManager liveTvManager, IHttpClient httpClient) + public static SatIpDiscovery Current; + + private readonly List _discoveredHosts = new List(); + + public List DiscoveredHosts + { + get { return _discoveredHosts.ToList(); } + } + + public SatIpDiscovery(IDeviceDiscovery deviceDiscovery, IServerConfigurationManager config, ILogger logger, ILiveTvManager liveTvManager, IHttpClient httpClient, IJsonSerializer json) { _deviceDiscovery = deviceDiscovery; _config = config; _logger = logger; _liveTvManager = liveTvManager; _httpClient = httpClient; + _json = json; + Current = this; } public void Run() @@ -66,26 +82,23 @@ namespace MediaBrowser.Server.Implementations.LiveTv.TunerHosts.SatIp try { - var options = GetConfiguration(); + if (_discoveredHosts.Any(i => string.Equals(i.Type, SatIpHost.DeviceType, StringComparison.OrdinalIgnoreCase) && string.Equals(location, i.Url, StringComparison.OrdinalIgnoreCase))) + { + return; + } - //if (options.TunerHosts.Any(i => - // string.Equals(i.Type, SatIpHost.DeviceType, StringComparison.OrdinalIgnoreCase) && - // UriEquals(i.Url, url))) - //{ - // return; - //} + _logger.Debug("Will attempt to add SAT device {0}", location); + var info = await GetInfo(location, CancellationToken.None).ConfigureAwait(false); - //// Strip off the port - //url = new Uri(url).GetComponents(UriComponents.AbsoluteUri & ~UriComponents.Port, UriFormat.UriEscaped).TrimEnd('/'); + _discoveredHosts.Add(info); + } + catch (OperationCanceledException) + { - //await TestUrl(url).ConfigureAwait(false); - - //await _liveTvManager.SaveTunerHost(new TunerHostInfo - //{ - // Type = SatIpHost.DeviceType, - // Url = url - - //}).ConfigureAwait(false); + } + catch (NotImplementedException) + { + } catch (Exception ex) { @@ -97,43 +110,121 @@ namespace MediaBrowser.Server.Implementations.LiveTv.TunerHosts.SatIp } } - private async Task TestUrl(string url) - { - // Test it by pulling down the lineup - using (await _httpClient.Get(new HttpRequestOptions - { - Url = string.Format("{0}/lineup.json", url), - CancellationToken = CancellationToken.None - })) - { - } - } - - 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("livetv"); - } - public void Dispose() { } + + public async Task GetInfo(string url, CancellationToken cancellationToken) + { + var result = new SatIpTunerHostInfo + { + Url = url, + IsEnabled = true, + Type = SatIpHost.DeviceType, + Tuners = 1, + TunersAvailable = 1 + }; + + using (var stream = await _httpClient.Get(url, cancellationToken).ConfigureAwait(false)) + { + using (var streamReader = new StreamReader(stream)) + { + // Use XmlReader for best performance + using (var reader = XmlReader.Create(streamReader)) + { + reader.MoveToContent(); + + // Loop through each element + while (reader.Read()) + { + if (reader.NodeType == XmlNodeType.Element) + { + switch (reader.Name) + { + case "device": + using (var subtree = reader.ReadSubtree()) + { + FillFromDeviceNode(result, subtree); + } + break; + default: + reader.Skip(); + break; + } + } + } + } + } + } + + if (string.IsNullOrWhiteSpace(result.Id)) + { + throw new NotImplementedException(); + } + + // Device hasn't implemented an m3u list + if (string.IsNullOrWhiteSpace(result.M3UUrl)) + { + result.IsEnabled = false; + } + + else if (!result.M3UUrl.StartsWith("http", StringComparison.OrdinalIgnoreCase)) + { + var fullM3uUrl = url.Substring(0, url.LastIndexOf('/')); + result.M3UUrl = fullM3uUrl + "/" + result.M3UUrl.TrimStart('/'); + } + + _logger.Debug("SAT device result: {0}", _json.SerializeToString(result)); + + return result; + } + + private void FillFromDeviceNode(SatIpTunerHostInfo info, XmlReader reader) + { + reader.MoveToContent(); + + while (reader.Read()) + { + if (reader.NodeType == XmlNodeType.Element) + { + switch (reader.Name) + { + case "UDN": + { + info.Id = reader.ReadElementContentAsString(); + break; + } + + case "satip:X_SATIPCAP": + case "X_SATIPCAP": + { + // DVBS2-2 + var value = reader.ReadElementContentAsString(); + // TODO + break; + } + + case "satip:X_SATIPM3U": + case "X_SATIPM3U": + { + // /channellist.lua?select=m3u + info.M3UUrl = reader.ReadElementContentAsString(); + break; + } + + default: + reader.Skip(); + break; + } + } + } + } + } + + public class SatIpTunerHostInfo : TunerHostInfo + { + public int Tuners { get; set; } + public int TunersAvailable { get; set; } + public string M3UUrl { get; set; } } } diff --git a/MediaBrowser.Server.Implementations/LiveTv/TunerHosts/SatIp/SatIpHost.cs b/MediaBrowser.Server.Implementations/LiveTv/TunerHosts/SatIp/SatIpHost.cs index 205cdf74ec..480f0edd04 100644 --- a/MediaBrowser.Server.Implementations/LiveTv/TunerHosts/SatIp/SatIpHost.cs +++ b/MediaBrowser.Server.Implementations/LiveTv/TunerHosts/SatIp/SatIpHost.cs @@ -1,45 +1,156 @@ -namespace MediaBrowser.Server.Implementations.LiveTv.TunerHosts.SatIp -{ - public class SatIpHost /*: BaseTunerHost*/ - { - //public SatIpHost(IConfigurationManager config, ILogger logger, IJsonSerializer jsonSerializer, IMediaEncoder mediaEncoder) - // : base(config, logger, jsonSerializer, mediaEncoder) - //{ - //} +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading; +using System.Threading.Tasks; +using CommonIO; +using MediaBrowser.Common.Configuration; +using MediaBrowser.Common.Extensions; +using MediaBrowser.Common.Net; +using MediaBrowser.Controller.LiveTv; +using MediaBrowser.Controller.MediaEncoding; +using MediaBrowser.Model.Dto; +using MediaBrowser.Model.Entities; +using MediaBrowser.Model.LiveTv; +using MediaBrowser.Model.Logging; +using MediaBrowser.Model.MediaInfo; +using MediaBrowser.Model.Serialization; - //protected override Task> GetChannelsInternal(TunerHostInfo tuner, CancellationToken cancellationToken) - //{ - // throw new NotImplementedException(); - //} +namespace MediaBrowser.Server.Implementations.LiveTv.TunerHosts.SatIp +{ + public class SatIpHost : BaseTunerHost, ITunerHost + { + private readonly IFileSystem _fileSystem; + private readonly IHttpClient _httpClient; + + public SatIpHost(IConfigurationManager config, ILogger logger, IJsonSerializer jsonSerializer, IMediaEncoder mediaEncoder, IFileSystem fileSystem, IHttpClient httpClient) + : base(config, logger, jsonSerializer, mediaEncoder) + { + _fileSystem = fileSystem; + _httpClient = httpClient; + } + + private const string ChannelIdPrefix = "sat_"; + + protected override async Task> GetChannelsInternal(TunerHostInfo tuner, CancellationToken cancellationToken) + { + var satInfo = (SatIpTunerHostInfo) tuner; + + return await new M3uParser(Logger, _fileSystem, _httpClient).Parse(satInfo.M3UUrl, ChannelIdPrefix, cancellationToken).ConfigureAwait(false); + } public static string DeviceType { get { return "satip"; } } - //public override string Type - //{ - // get { return DeviceType; } - //} + public override string Type + { + get { return DeviceType; } + } - //protected override Task> GetChannelStreamMediaSources(TunerHostInfo tuner, string channelId, CancellationToken cancellationToken) - //{ - // throw new NotImplementedException(); - //} + protected override async Task> GetChannelStreamMediaSources(TunerHostInfo tuner, string channelId, CancellationToken cancellationToken) + { + var urlHash = tuner.Url.GetMD5().ToString("N"); + var prefix = ChannelIdPrefix + urlHash; + if (!channelId.StartsWith(prefix, StringComparison.OrdinalIgnoreCase)) + { + return null; + } - //protected override Task GetChannelStream(TunerHostInfo tuner, string channelId, string streamId, CancellationToken cancellationToken) - //{ - // throw new NotImplementedException(); - //} + var channels = await GetChannels(tuner, true, cancellationToken).ConfigureAwait(false); + var m3uchannels = channels.Cast(); + 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; + } - //protected override Task IsAvailableInternal(TunerHostInfo tuner, string channelId, CancellationToken cancellationToken) - //{ - // throw new NotImplementedException(); - //} + var mediaSource = new MediaSourceInfo + { + Path = channel.Path, + Protocol = protocol, + MediaStreams = new List + { + 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 - //protected override bool IsValidChannelId(string channelId) - //{ - // throw new NotImplementedException(); - //} + } + }, + RequiresOpening = false, + RequiresClosing = false + }; + + return new List { mediaSource }; + } + return new List { }; + } + + protected override async Task GetChannelStream(TunerHostInfo tuner, string channelId, string streamId, CancellationToken cancellationToken) + { + var sources = await GetChannelStreamMediaSources(tuner, channelId, cancellationToken).ConfigureAwait(false); + + return sources.First(); + } + + protected override async Task IsAvailableInternal(TunerHostInfo tuner, string channelId, CancellationToken cancellationToken) + { + var updatedInfo = await SatIpDiscovery.Current.GetInfo(tuner.Url, cancellationToken).ConfigureAwait(false); + + return updatedInfo.TunersAvailable > 0; + } + + protected override bool IsValidChannelId(string channelId) + { + return channelId.StartsWith(ChannelIdPrefix, StringComparison.OrdinalIgnoreCase); + } + + protected override List GetTunerHosts() + { + return SatIpDiscovery.Current.DiscoveredHosts; + } + + public string Name + { + get { return "Sat IP"; } + } + + public Task> 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); + } } } diff --git a/MediaBrowser.Server.Implementations/MediaBrowser.Server.Implementations.csproj b/MediaBrowser.Server.Implementations/MediaBrowser.Server.Implementations.csproj index 80592c7243..21066a9f44 100644 --- a/MediaBrowser.Server.Implementations/MediaBrowser.Server.Implementations.csproj +++ b/MediaBrowser.Server.Implementations/MediaBrowser.Server.Implementations.csproj @@ -234,6 +234,7 @@ +