diff --git a/MediaBrowser.Api/Playback/BaseStreamingService.cs b/MediaBrowser.Api/Playback/BaseStreamingService.cs index e7885a3f8..8505b5d3a 100644 --- a/MediaBrowser.Api/Playback/BaseStreamingService.cs +++ b/MediaBrowser.Api/Playback/BaseStreamingService.cs @@ -924,7 +924,7 @@ namespace MediaBrowser.Api.Playback state.IsoMount = await IsoManager.Mount(state.MediaPath, cancellationTokenSource.Token).ConfigureAwait(false); } - if (state.MediaSource.RequiresOpening) + if (state.MediaSource.RequiresOpening ?? false) { var liveStreamResponse = await MediaSourceManager.OpenLiveStream(new LiveStreamRequest { diff --git a/MediaBrowser.Api/Playback/StreamState.cs b/MediaBrowser.Api/Playback/StreamState.cs index 02b7720a4..4df696096 100644 --- a/MediaBrowser.Api/Playback/StreamState.cs +++ b/MediaBrowser.Api/Playback/StreamState.cs @@ -185,7 +185,7 @@ namespace MediaBrowser.Api.Playback private async void DisposeLiveStream() { - if (MediaSource.RequiresClosing && string.IsNullOrWhiteSpace(Request.LiveStreamId)) + if ((MediaSource.RequiresClosing ?? false) && string.IsNullOrWhiteSpace(Request.LiveStreamId)) { try { diff --git a/MediaBrowser.Controller/LiveTv/ITunerHost.cs b/MediaBrowser.Controller/LiveTv/ITunerHost.cs index 38ed43bd9..c9a96a9ca 100644 --- a/MediaBrowser.Controller/LiveTv/ITunerHost.cs +++ b/MediaBrowser.Controller/LiveTv/ITunerHost.cs @@ -47,6 +47,14 @@ namespace MediaBrowser.Controller.LiveTv /// Task<MediaSourceInfo>. Task GetChannelStream(TunerHostInfo info, string channelId, string streamId, CancellationToken cancellationToken); /// + /// Gets the channel stream media sources. + /// + /// The information. + /// The channel identifier. + /// The cancellation token. + /// Task<List<MediaSourceInfo>>. + Task> GetChannelStreamMediaSources(TunerHostInfo info, string channelId, CancellationToken cancellationToken); + /// /// Validates the specified information. /// /// The information. diff --git a/MediaBrowser.MediaEncoding/Encoder/BaseEncoder.cs b/MediaBrowser.MediaEncoding/Encoder/BaseEncoder.cs index fbfe79272..9153045e6 100644 --- a/MediaBrowser.MediaEncoding/Encoder/BaseEncoder.cs +++ b/MediaBrowser.MediaEncoding/Encoder/BaseEncoder.cs @@ -436,7 +436,7 @@ namespace MediaBrowser.MediaEncoding.Encoder state.IsoMount = await IsoManager.Mount(state.MediaPath, cancellationToken).ConfigureAwait(false); } - if (state.MediaSource.RequiresOpening) + if (state.MediaSource.RequiresOpening ?? false) { var liveStreamResponse = await MediaSourceManager.OpenLiveStream(new LiveStreamRequest { diff --git a/MediaBrowser.MediaEncoding/Encoder/EncodingJob.cs b/MediaBrowser.MediaEncoding/Encoder/EncodingJob.cs index efce5abb0..bb32ac95b 100644 --- a/MediaBrowser.MediaEncoding/Encoder/EncodingJob.cs +++ b/MediaBrowser.MediaEncoding/Encoder/EncodingJob.cs @@ -137,7 +137,7 @@ namespace MediaBrowser.MediaEncoding.Encoder private async void DisposeLiveStream() { - if (MediaSource.RequiresClosing) + if (MediaSource.RequiresClosing ?? false) { try { diff --git a/MediaBrowser.Model/Dto/MediaSourceInfo.cs b/MediaBrowser.Model/Dto/MediaSourceInfo.cs index 8897edcbd..75edc6a52 100644 --- a/MediaBrowser.Model/Dto/MediaSourceInfo.cs +++ b/MediaBrowser.Model/Dto/MediaSourceInfo.cs @@ -26,9 +26,9 @@ namespace MediaBrowser.Model.Dto public bool SupportsDirectStream { get; set; } public bool SupportsDirectPlay { get; set; } - public bool RequiresOpening { get; set; } + public bool? RequiresOpening { get; set; } public string OpenToken { get; set; } - public bool RequiresClosing { get; set; } + public bool? RequiresClosing { get; set; } public string LiveStreamId { get; set; } public int? BufferMs { get; set; } diff --git a/MediaBrowser.Model/LiveTv/LiveTvOptions.cs b/MediaBrowser.Model/LiveTv/LiveTvOptions.cs index 90cd8924d..3fc841645 100644 --- a/MediaBrowser.Model/LiveTv/LiveTvOptions.cs +++ b/MediaBrowser.Model/LiveTv/LiveTvOptions.cs @@ -34,5 +34,6 @@ namespace MediaBrowser.Model.LiveTv public string Password { get; set; } public string ListingsId { get; set; } public string ZipCode { get; set; } + public string Country { get; set; } } } \ No newline at end of file diff --git a/MediaBrowser.Server.Implementations/Library/MediaSourceManager.cs b/MediaBrowser.Server.Implementations/Library/MediaSourceManager.cs index 9b46a8057..765acd578 100644 --- a/MediaBrowser.Server.Implementations/Library/MediaSourceManager.cs +++ b/MediaBrowser.Server.Implementations/Library/MediaSourceManager.cs @@ -439,7 +439,7 @@ namespace MediaBrowser.Server.Implementations.Library LiveStreamInfo current; if (_openStreams.TryGetValue(id, out current)) { - if (current.MediaSource.RequiresClosing) + if (current.MediaSource.RequiresClosing ?? false) { var tuple = GetProvider(id); diff --git a/MediaBrowser.Server.Implementations/LiveTv/EmbyTV/EmbyTV.cs b/MediaBrowser.Server.Implementations/LiveTv/EmbyTV/EmbyTV.cs index 37b6bf086..c32b8da10 100644 --- a/MediaBrowser.Server.Implementations/LiveTv/EmbyTV/EmbyTV.cs +++ b/MediaBrowser.Server.Implementations/LiveTv/EmbyTV/EmbyTV.cs @@ -1,5 +1,6 @@ using MediaBrowser.Common; using MediaBrowser.Common.Configuration; +using MediaBrowser.Common.Extensions; using MediaBrowser.Common.Net; using MediaBrowser.Controller.Drawing; using MediaBrowser.Controller.LiveTv; @@ -74,20 +75,17 @@ namespace MediaBrowser.Server.Implementations.LiveTv.EmbyTV var status = new LiveTvServiceStatusInfo(); var list = new List(); - foreach (var host in _liveTvManager.TunerHosts) + foreach (var hostInstance in GetTunerHosts()) { - foreach (var hostInstance in host.GetTunerHosts()) + try { - try - { - var tuners = await host.GetTunerInfos(hostInstance, cancellationToken).ConfigureAwait(false); + var tuners = await hostInstance.Item1.GetTunerInfos(hostInstance.Item2, cancellationToken).ConfigureAwait(false); - list.AddRange(tuners); - } - catch (Exception ex) - { - _logger.ErrorException("Error getting tuners", ex); - } + list.AddRange(tuners); + } + catch (Exception ex) + { + _logger.ErrorException("Error getting tuners", ex); } } @@ -102,20 +100,23 @@ namespace MediaBrowser.Server.Implementations.LiveTv.EmbyTV { var list = new List(); - foreach (var host in _liveTvManager.TunerHosts) + foreach (var hostInstance in GetTunerHosts()) { - foreach (var hostInstance in host.GetTunerHosts()) + try { - try - { - var channels = await host.GetChannels(hostInstance, cancellationToken).ConfigureAwait(false); + var channels = await hostInstance.Item1.GetChannels(hostInstance.Item2, cancellationToken).ConfigureAwait(false); + var newChannels = channels.ToList(); - list.AddRange(channels); - } - catch (Exception ex) + foreach (var channel in newChannels) { - _logger.ErrorException("Error getting channels", ex); + channel.Id = hostInstance.Item1.Type.GetMD5().ToString("N") + "-" + channel.Id; } + + list.AddRange(newChannels); + } + catch (Exception ex) + { + _logger.ErrorException("Error getting channels", ex); } } @@ -130,6 +131,19 @@ namespace MediaBrowser.Server.Implementations.LiveTv.EmbyTV return list; } + private List> GetTunerHosts() + { + return GetConfiguration().TunerHosts + .Select(i => + { + var provider = _liveTvManager.TunerHosts.FirstOrDefault(l => string.Equals(l.Type, i.Type, StringComparison.OrdinalIgnoreCase)); + + return provider == null ? null : new Tuple(provider, i); + }) + .Where(i => i != null) + .ToList(); + } + public Task CancelSeriesTimerAsync(string timerId, CancellationToken cancellationToken) { var remove = _seriesTimerProvider.GetAll().SingleOrDefault(r => r.Id == timerId); @@ -255,14 +269,27 @@ namespace MediaBrowser.Server.Implementations.LiveTv.EmbyTV return Task.FromResult((IEnumerable)_seriesTimerProvider.GetAll()); } + private string GetOriginalChannelId(string channelId) + { + var parts = channelId.Split('-'); + + return string.Join("-", parts.Skip(1).ToArray()); + } + public async Task> GetProgramsAsync(string channelId, DateTime startDateUtc, DateTime endDateUtc, CancellationToken cancellationToken) { foreach (var provider in GetListingProviders()) { - var programs = await provider.Item1.GetProgramsAsync(provider.Item2, channelId, startDateUtc, endDateUtc, cancellationToken) + var programs = await provider.Item1.GetProgramsAsync(provider.Item2, GetOriginalChannelId(channelId), startDateUtc, endDateUtc, cancellationToken) .ConfigureAwait(false); var list = programs.ToList(); + // Replace the value that came from the provider with a normalized value + foreach (var program in list) + { + program.ChannelId = channelId; + } + if (list.Count > 0) { return list; @@ -290,14 +317,67 @@ namespace MediaBrowser.Server.Implementations.LiveTv.EmbyTV throw new NotImplementedException(); } - public Task GetChannelStream(string channelId, string streamId, CancellationToken cancellationToken) + public async Task GetChannelStream(string channelId, string streamId, CancellationToken cancellationToken) { - throw new NotImplementedException(); + _logger.Info("Streaming Channel " + channelId); + + var configurationId = channelId.Split('-')[0]; + + foreach (var hostInstance in GetTunerHosts()) + { + if (!string.Equals(configurationId, hostInstance.Item1.Type.GetMD5().ToString("N"), StringComparison.OrdinalIgnoreCase)) + { + continue; + } + + if (!string.IsNullOrWhiteSpace(streamId)) + { + var originalStreamId = string.Join("-", streamId.Split('-').Skip(1).ToArray()); + + if (!string.Equals(hostInstance.Item2.Id, originalStreamId, StringComparison.OrdinalIgnoreCase)) + { + continue; + } + } + + MediaSourceInfo mediaSourceInfo = null; + try + { + mediaSourceInfo = await hostInstance.Item1.GetChannelStream(hostInstance.Item2, GetOriginalChannelId(channelId), streamId, cancellationToken).ConfigureAwait(false); + } + catch (ApplicationException e) + { + _logger.Info(e.Message); + continue; + } + + mediaSourceInfo.Id = Guid.NewGuid().ToString("N"); + return mediaSourceInfo; + } + + throw new ApplicationException("Tuner not found."); } - public Task> GetChannelStreamMediaSources(string channelId, CancellationToken cancellationToken) + public async Task> GetChannelStreamMediaSources(string channelId, CancellationToken cancellationToken) { - throw new NotImplementedException(); + var configurationId = channelId.Split('-')[0]; + + foreach (var hostInstance in GetTunerHosts()) + { + if (string.Equals(configurationId, hostInstance.Item1.Type.GetMD5().ToString("N"), StringComparison.OrdinalIgnoreCase)) + { + var sources = await hostInstance.Item1.GetChannelStreamMediaSources(hostInstance.Item2, GetOriginalChannelId(channelId), cancellationToken).ConfigureAwait(false); + + foreach (var source in sources) + { + source.Id = hostInstance.Item2.Id + "-" + source.Id; + } + + return sources; + } + } + + throw new ApplicationException("Tuner not found."); } public Task> GetRecordingStreamMediaSources(string recordingId, CancellationToken cancellationToken) diff --git a/MediaBrowser.Server.Implementations/LiveTv/EmbyTV/ItemDataProvider.cs b/MediaBrowser.Server.Implementations/LiveTv/EmbyTV/ItemDataProvider.cs index e7feeee5a..75dec5f97 100644 --- a/MediaBrowser.Server.Implementations/LiveTv/EmbyTV/ItemDataProvider.cs +++ b/MediaBrowser.Server.Implementations/LiveTv/EmbyTV/ItemDataProvider.cs @@ -68,9 +68,12 @@ namespace MediaBrowser.Server.Implementations.LiveTv.EmbyTV private void UpdateList(List newList) { + var file = _dataPath + ".json"; + Directory.CreateDirectory(Path.GetDirectoryName(file)); + lock (_fileDataLock) { - _jsonSerializer.SerializeToFile(newList, _dataPath + ".json"); + _jsonSerializer.SerializeToFile(newList, file); _items = newList; } } diff --git a/MediaBrowser.Server.Implementations/LiveTv/Listings/SchedulesDirect.cs b/MediaBrowser.Server.Implementations/LiveTv/Listings/SchedulesDirect.cs index ed265d416..72a965c6a 100644 --- a/MediaBrowser.Server.Implementations/LiveTv/Listings/SchedulesDirect.cs +++ b/MediaBrowser.Server.Implementations/LiveTv/Listings/SchedulesDirect.cs @@ -218,7 +218,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv.Listings private ProgramInfo GetProgram(string channel, ScheduleDirect.Program programInfo, ScheduleDirect.ProgramDetails details) { - _logger.Debug("Show type is: " + (details.showType ?? "No ShowType")); + //_logger.Debug("Show type is: " + (details.showType ?? "No ShowType")); DateTime startAt = DateTime.ParseExact(programInfo.airDateTime, "yyyy'-'MM'-'dd'T'HH':'mm':'ss'Z'", CultureInfo.InvariantCulture); DateTime endAt = startAt.AddSeconds(programInfo.duration); @@ -401,7 +401,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv.Listings _logger.Info("Headends on account "); var countryParam = string.Equals("ca", country, StringComparison.OrdinalIgnoreCase) - ? "Canada" + ? "can" : "USA"; var options = new HttpRequestOptions() @@ -562,6 +562,44 @@ namespace MediaBrowser.Server.Implementations.LiveTv.Listings get { return "SchedulesDirect"; } } + private async Task HasLineup(ListingsProviderInfo info, CancellationToken cancellationToken) + { + var token = await GetToken(info, cancellationToken); + + _logger.Info("Headends on account "); + + var options = new HttpRequestOptions() + { + Url = ApiUrl + "/lineups", + UserAgent = UserAgent, + CancellationToken = cancellationToken + }; + + options.RequestHeaders["token"] = token; + + using (Stream responce = await _httpClient.Get(options).ConfigureAwait(false)) + { + var root = _jsonSerializer.DeserializeFromStream(responce); + + return root.lineups.Any(i => string.Equals(info.ListingsId, i.lineup, StringComparison.OrdinalIgnoreCase)); + } + } + + public async Task Validate(ListingsProviderInfo info) + { + var hasLineup = await HasLineup(info, CancellationToken.None).ConfigureAwait(false); + + if (!hasLineup) + { + await AddLineupToAccount(info, CancellationToken.None).ConfigureAwait(false); + } + } + + public Task> GetLineups(ListingsProviderInfo info, string country, string location) + { + return GetHeadends(info, country, location, CancellationToken.None); + } + public class ScheduleDirect { public class Token @@ -841,14 +879,5 @@ namespace MediaBrowser.Server.Implementations.LiveTv.Listings } - public async Task Validate(ListingsProviderInfo info) - { - //await AddLineupToAccount(info, CancellationToken.None).ConfigureAwait(false); - } - - public Task> GetLineups(ListingsProviderInfo info, string country, string location) - { - return GetHeadends(info, country, location, CancellationToken.None); - } } } diff --git a/MediaBrowser.Server.Implementations/LiveTv/LiveTvManager.cs b/MediaBrowser.Server.Implementations/LiveTv/LiveTvManager.cs index 5be90e6cc..6ef565129 100644 --- a/MediaBrowser.Server.Implementations/LiveTv/LiveTvManager.cs +++ b/MediaBrowser.Server.Implementations/LiveTv/LiveTvManager.cs @@ -367,7 +367,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv info = await service.GetChannelStream(channel.ExternalId, mediaSourceId, cancellationToken).ConfigureAwait(false); info.RequiresClosing = true; - if (info.RequiresClosing) + if (info.RequiresClosing ?? false) { var idPrefix = service.GetType().FullName.GetMD5().ToString("N") + "_"; @@ -384,7 +384,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv info = await service.GetRecordingStream(recording.ExternalId, null, cancellationToken).ConfigureAwait(false); info.RequiresClosing = true; - if (info.RequiresClosing) + if (info.RequiresClosing ?? false) { var idPrefix = service.GetType().FullName.GetMD5().ToString("N") + "_"; diff --git a/MediaBrowser.Server.Implementations/LiveTv/LiveTvMediaSourceProvider.cs b/MediaBrowser.Server.Implementations/LiveTv/LiveTvMediaSourceProvider.cs index 5ebb79629..cf34b6b99 100644 --- a/MediaBrowser.Server.Implementations/LiveTv/LiveTvMediaSourceProvider.cs +++ b/MediaBrowser.Server.Implementations/LiveTv/LiveTvMediaSourceProvider.cs @@ -53,7 +53,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv // Do not use a pipe here because Roku http requests to the server will fail, without any explicit error message. private const char StreamIdDelimeter = '_'; - private const string StreamIdDelimeterString = "|"; + private const string StreamIdDelimeterString = "_"; private async Task> GetMediaSourcesInternal(ILiveTvItem item, CancellationToken cancellationToken) { @@ -86,14 +86,22 @@ namespace MediaBrowser.Server.Implementations.LiveTv foreach (var source in list) { source.Type = MediaSourceType.Default; - source.RequiresOpening = true; - source.BufferMs = source.BufferMs ?? 1500; - var openKeys = new List(); - openKeys.Add(item.GetType().Name); - openKeys.Add(item.Id.ToString("N")); - openKeys.Add(source.Id ?? string.Empty); - source.OpenToken = string.Join(StreamIdDelimeterString, openKeys.ToArray()); + if (!source.RequiresOpening.HasValue) + { + source.RequiresOpening = true; + } + + if (source.RequiresOpening.HasValue && source.RequiresOpening.Value) + { + var openKeys = new List(); + openKeys.Add(item.GetType().Name); + openKeys.Add(item.Id.ToString("N")); + openKeys.Add(source.Id ?? string.Empty); + source.OpenToken = string.Join(StreamIdDelimeterString, openKeys.ToArray()); + } + + source.BufferMs = source.BufferMs ?? 1500; // Dummy this up so that direct play checks can still run if (string.IsNullOrEmpty(source.Path) && source.Protocol == MediaProtocol.Http) diff --git a/MediaBrowser.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunDiscovery.cs b/MediaBrowser.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunDiscovery.cs index 4777003d6..cc2bb2d52 100644 --- a/MediaBrowser.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunDiscovery.cs +++ b/MediaBrowser.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunDiscovery.cs @@ -72,6 +72,9 @@ namespace MediaBrowser.Server.Implementations.LiveTv.TunerHosts.HdHomerun return; } + // Strip off the port + url = new Uri(url).GetComponents(UriComponents.AbsoluteUri & ~UriComponents.Port, UriFormat.UriEscaped); + await _liveTvManager.SaveTunerHost(new TunerHostInfo { Type = HdHomerunHost.DeviceType, @@ -103,13 +106,8 @@ namespace MediaBrowser.Server.Implementations.LiveTv.TunerHosts.HdHomerun url = url.TrimEnd('/'); - // If there isn't a port, add the default port of 80 - if (url.Split(':').Length < 3) - { - url += ":80"; - } - - return url; + // Strip off the port + return new Uri(url).GetComponents(UriComponents.AbsoluteUri & ~UriComponents.Port, UriFormat.UriEscaped); } private LiveTvOptions GetConfiguration() diff --git a/MediaBrowser.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunHost.cs b/MediaBrowser.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunHost.cs index 187569ab4..d9f1541c8 100644 --- a/MediaBrowser.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunHost.cs +++ b/MediaBrowser.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunHost.cs @@ -51,7 +51,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv.TunerHosts.HdHomerun { var options = new HttpRequestOptions { - Url = string.Format("{0}/lineup.json", GetApiUrl(info)), + Url = string.Format("{0}/lineup.json", GetApiUrl(info, false)), CancellationToken = cancellationToken }; using (var stream = await _httpClient.Get(options)) @@ -79,7 +79,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv.TunerHosts.HdHomerun using (var stream = await _httpClient.Get(new HttpRequestOptions() { - Url = string.Format("{0}/", GetApiUrl(info)), + Url = string.Format("{0}/", GetApiUrl(info, false)), CancellationToken = cancellationToken })) { @@ -97,7 +97,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv.TunerHosts.HdHomerun using (var stream = await _httpClient.Get(new HttpRequestOptions() { - Url = string.Format("{0}/tuners.html", GetApiUrl(info)), + Url = string.Format("{0}/tuners.html", GetApiUrl(info, false)), CancellationToken = cancellationToken })) { @@ -128,7 +128,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv.TunerHosts.HdHomerun } } - public string GetApiUrl(TunerHostInfo info) + private string GetApiUrl(TunerHostInfo info, bool isPlayback) { var url = info.Url; @@ -137,7 +137,16 @@ namespace MediaBrowser.Server.Implementations.LiveTv.TunerHosts.HdHomerun url = "http://" + url; } - return url.TrimEnd('/'); + 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) @@ -187,21 +196,13 @@ namespace MediaBrowser.Server.Implementations.LiveTv.TunerHosts.HdHomerun return GetConfiguration().TunerHosts.Where(i => string.Equals(i.Type, Type, StringComparison.OrdinalIgnoreCase)).ToList(); } - public async Task GetChannelStream(TunerHostInfo info, string channelId, string streamId, CancellationToken cancellationToken) + private MediaSourceInfo GetMediaSource(TunerHostInfo info, string channelId, string profile) { - var channels = await GetChannels(info, cancellationToken).ConfigureAwait(false); - var tuners = await GetTunerInfos(info, cancellationToken).ConfigureAwait(false); - - var channel = channels.FirstOrDefault(c => string.Equals(c.Id, channelId, StringComparison.OrdinalIgnoreCase)); - if (channel != null) + var mediaSource = new MediaSourceInfo { - if (tuners.FindIndex(t => t.Status == LiveTvTunerStatus.Available) >= 0) - { - return new MediaSourceInfo - { - Path = GetApiUrl(info) + "/auto/v" + channelId, - Protocol = MediaProtocol.Http, - MediaStreams = new List + Path = GetApiUrl(info, true) + "/auto/v" + channelId, + Protocol = MediaProtocol.Http, + MediaStreams = new List { new MediaStream { @@ -217,15 +218,28 @@ namespace MediaBrowser.Server.Implementations.LiveTv.TunerHosts.HdHomerun Index = -1 } - } - }; - } + }, + RequiresOpening = false, + RequiresClosing = false, + BufferMs = 1000 + }; - throw new ApplicationException("No tuners avaliable."); - } - throw new ApplicationException("Channel not found."); + return mediaSource; } + public Task> GetChannelStreamMediaSources(TunerHostInfo info, string channelId, CancellationToken cancellationToken) + { + var list = new List(); + + list.Add(GetMediaSource(info, channelId, null)); + + return Task.FromResult(list); + } + + public async Task GetChannelStream(TunerHostInfo info, string channelId, string streamId, CancellationToken cancellationToken) + { + return GetMediaSource(info, channelId, null); + } public async Task Validate(TunerHostInfo info) { diff --git a/MediaBrowser.Server.Implementations/LiveTv/TunerHosts/M3UTunerHost.cs b/MediaBrowser.Server.Implementations/LiveTv/TunerHosts/M3UTunerHost.cs index e91bd0f0b..91f25bbee 100644 --- a/MediaBrowser.Server.Implementations/LiveTv/TunerHosts/M3UTunerHost.cs +++ b/MediaBrowser.Server.Implementations/LiveTv/TunerHosts/M3UTunerHost.cs @@ -171,7 +171,9 @@ namespace MediaBrowser.Server.Implementations.LiveTv.TunerHosts Index = -1 } - } + }, + RequiresOpening = false, + RequiresClosing = false }; } throw new ApplicationException("Host doesnt provide this channel"); @@ -193,5 +195,11 @@ namespace MediaBrowser.Server.Implementations.LiveTv.TunerHosts throw new FileNotFoundException(); } } + + + public Task> GetChannelStreamMediaSources(TunerHostInfo info, string channelId, CancellationToken cancellationToken) + { + throw new NotImplementedException(); + } } } diff --git a/MediaBrowser.Server.Implementations/Localization/Server/server.json b/MediaBrowser.Server.Implementations/Localization/Server/server.json index 24df7c983..194d406f3 100644 --- a/MediaBrowser.Server.Implementations/Localization/Server/server.json +++ b/MediaBrowser.Server.Implementations/Localization/Server/server.json @@ -1489,5 +1489,5 @@ "GuideProviderListingsStep": "Step 2: Select Listings", "GuideProviderLoginStep": "Step 1: Login", "LabelLineup": "Lineup", - "MessageTunerDeviceNotListed": "Is your tuner device not listed? Try installing an external service plugin for more Live TV options." + "MessageTunerDeviceNotListed": "Is your tuner device not listed? Try installing an external service provider for more Live TV options." }