From 20b990dc9a01f00e561181ad48ae73d62bcb2427 Mon Sep 17 00:00:00 2001 From: Luke Pulverenti Date: Mon, 20 Jul 2015 14:32:55 -0400 Subject: start pulling in EmbyTV --- MediaBrowser.Model/LiveTv/LiveTvOptions.cs | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) (limited to 'MediaBrowser.Model/LiveTv') diff --git a/MediaBrowser.Model/LiveTv/LiveTvOptions.cs b/MediaBrowser.Model/LiveTv/LiveTvOptions.cs index c6f6ed84ce..303b12af7d 100644 --- a/MediaBrowser.Model/LiveTv/LiveTvOptions.cs +++ b/MediaBrowser.Model/LiveTv/LiveTvOptions.cs @@ -1,13 +1,24 @@ -namespace MediaBrowser.Model.LiveTv +using System.Collections.Generic; + +namespace MediaBrowser.Model.LiveTv { public class LiveTvOptions { public int? GuideDays { get; set; } public bool EnableMovieProviders { get; set; } + public List TunerHosts { get; set; } + public string RecordingPath { get; set; } public LiveTvOptions() { EnableMovieProviders = true; + TunerHosts = new List(); } } + + public class TunerHostInfo + { + public string Url { get; set; } + public string Type { get; set; } + } } \ No newline at end of file -- cgit v1.2.3 From 9457ff7ce87e4752a7f51381b309604ee08f030e Mon Sep 17 00:00:00 2001 From: Luke Pulverenti Date: Tue, 21 Jul 2015 00:22:46 -0400 Subject: completed tuner hosts --- MediaBrowser.Api/LiveTv/LiveTvService.cs | 49 +++++++++++++++++++++- .../LiveTv/IListingsProvider.cs | 7 +++- .../LiveTv/LiveTvServiceStatusInfo.cs | 8 +++- MediaBrowser.Model/LiveTv/LiveTvOptions.cs | 1 + MediaBrowser.Model/LiveTv/LiveTvServiceInfo.cs | 5 +++ .../LiveTv/EmbyTV/EmbyTV.cs | 4 ++ .../LiveTv/Listings/SchedulesDirect.cs | 16 +++++++ .../LiveTv/LiveTvManager.cs | 1 + .../LiveTv/TunerHosts/HdHomerun.cs | 29 +++++++++++-- .../Localization/JavaScript/javascript.json | 3 +- .../Localization/Server/server.json | 9 +++- .../MediaBrowser.Server.Implementations.csproj | 1 + 12 files changed, 123 insertions(+), 10 deletions(-) create mode 100644 MediaBrowser.Server.Implementations/LiveTv/Listings/SchedulesDirect.cs (limited to 'MediaBrowser.Model/LiveTv') diff --git a/MediaBrowser.Api/LiveTv/LiveTvService.cs b/MediaBrowser.Api/LiveTv/LiveTvService.cs index c474642d5d..49ba001cef 100644 --- a/MediaBrowser.Api/LiveTv/LiveTvService.cs +++ b/MediaBrowser.Api/LiveTv/LiveTvService.cs @@ -1,4 +1,5 @@ -using MediaBrowser.Controller.Dto; +using MediaBrowser.Common.Configuration; +using MediaBrowser.Controller.Dto; using MediaBrowser.Controller.Library; using MediaBrowser.Controller.LiveTv; using MediaBrowser.Controller.Net; @@ -330,15 +331,31 @@ namespace MediaBrowser.Api.LiveTv public string UserId { get; set; } } + [Route("/LiveTv/TunerHosts", "POST", Summary = "Adds a tuner host")] + [Authenticated] + public class AddTunerHost : TunerHostInfo, IReturnVoid + { + } + + [Route("/LiveTv/TunerHosts", "DELETE", Summary = "Deletes a tuner host")] + [Authenticated] + public class DeleteTunerHost : IReturnVoid + { + [ApiMember(Name = "Id", Description = "Tuner host id", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "DELETE")] + public string Id { get; set; } + } + public class LiveTvService : BaseApiService { private readonly ILiveTvManager _liveTvManager; private readonly IUserManager _userManager; + private readonly IConfigurationManager _config; - public LiveTvService(ILiveTvManager liveTvManager, IUserManager userManager) + public LiveTvService(ILiveTvManager liveTvManager, IUserManager userManager, IConfigurationManager config) { _liveTvManager = liveTvManager; _userManager = userManager; + _config = config; } private void AssertUserCanManageLiveTv() @@ -356,6 +373,34 @@ namespace MediaBrowser.Api.LiveTv } } + public void Post(AddTunerHost request) + { + var config = GetConfiguration(); + + config.TunerHosts.Add(new TunerHostInfo + { + Id = Guid.NewGuid().ToString("N"), + Url = request.Url, + Type = request.Type + }); + + _config.SaveConfiguration("livetv", config); + } + + public void Delete(DeleteTunerHost request) + { + var config = GetConfiguration(); + + config.TunerHosts = config.TunerHosts.Where(i => !string.Equals(request.Id, i.Id, StringComparison.OrdinalIgnoreCase)).ToList(); + + _config.SaveConfiguration("livetv", config); + } + + private LiveTvOptions GetConfiguration() + { + return _config.GetConfiguration("livetv"); + } + public async Task Get(GetLiveTvInfo request) { var info = await _liveTvManager.GetLiveTvInfo(CancellationToken.None).ConfigureAwait(false); diff --git a/MediaBrowser.Controller/LiveTv/IListingsProvider.cs b/MediaBrowser.Controller/LiveTv/IListingsProvider.cs index 2cef455e8b..75ca7e0dcc 100644 --- a/MediaBrowser.Controller/LiveTv/IListingsProvider.cs +++ b/MediaBrowser.Controller/LiveTv/IListingsProvider.cs @@ -1,7 +1,12 @@ - +using System; +using System.Collections.Generic; +using System.Threading; +using System.Threading.Tasks; + namespace MediaBrowser.Controller.LiveTv { public interface IListingsProvider { + Task> GetProgramsAsync(ChannelInfo channel, DateTime startDateUtc, DateTime endDateUtc, CancellationToken cancellationToken); } } diff --git a/MediaBrowser.Controller/LiveTv/LiveTvServiceStatusInfo.cs b/MediaBrowser.Controller/LiveTv/LiveTvServiceStatusInfo.cs index 0cb064aba3..4da238acf5 100644 --- a/MediaBrowser.Controller/LiveTv/LiveTvServiceStatusInfo.cs +++ b/MediaBrowser.Controller/LiveTv/LiveTvServiceStatusInfo.cs @@ -34,10 +34,16 @@ namespace MediaBrowser.Controller.LiveTv /// /// The tuners. public List Tuners { get; set; } - + /// + /// Gets or sets a value indicating whether this instance is visible. + /// + /// true if this instance is visible; otherwise, false. + public bool IsVisible { get; set; } + public LiveTvServiceStatusInfo() { Tuners = new List(); + IsVisible = true; } } } diff --git a/MediaBrowser.Model/LiveTv/LiveTvOptions.cs b/MediaBrowser.Model/LiveTv/LiveTvOptions.cs index 303b12af7d..2ca7397c1e 100644 --- a/MediaBrowser.Model/LiveTv/LiveTvOptions.cs +++ b/MediaBrowser.Model/LiveTv/LiveTvOptions.cs @@ -18,6 +18,7 @@ namespace MediaBrowser.Model.LiveTv public class TunerHostInfo { + public string Id { get; set; } public string Url { get; set; } public string Type { get; set; } } diff --git a/MediaBrowser.Model/LiveTv/LiveTvServiceInfo.cs b/MediaBrowser.Model/LiveTv/LiveTvServiceInfo.cs index 264870ffbb..25d3b289f0 100644 --- a/MediaBrowser.Model/LiveTv/LiveTvServiceInfo.cs +++ b/MediaBrowser.Model/LiveTv/LiveTvServiceInfo.cs @@ -42,6 +42,11 @@ namespace MediaBrowser.Model.LiveTv /// /// true if this instance has update available; otherwise, false. public bool HasUpdateAvailable { get; set; } + /// + /// Gets or sets a value indicating whether this instance is visible. + /// + /// true if this instance is visible; otherwise, false. + public bool IsVisible { get; set; } public List Tuners { get; set; } diff --git a/MediaBrowser.Server.Implementations/LiveTv/EmbyTV/EmbyTV.cs b/MediaBrowser.Server.Implementations/LiveTv/EmbyTV/EmbyTV.cs index d0a2712606..b71d62f433 100644 --- a/MediaBrowser.Server.Implementations/LiveTv/EmbyTV/EmbyTV.cs +++ b/MediaBrowser.Server.Implementations/LiveTv/EmbyTV/EmbyTV.cs @@ -20,6 +20,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv.EmbyTV { public class EmbyTV : ILiveTvService, IDisposable { + private readonly IApplicationHost _appHpst; private readonly ILogger _logger; private readonly IHttpClient _httpClient; private readonly IConfigurationManager _config; @@ -32,6 +33,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv.EmbyTV public EmbyTV(IApplicationHost appHost, ILogger logger, IJsonSerializer jsonSerializer, IHttpClient httpClient, IConfigurationManager config) { + _appHpst = appHost; _logger = logger; _httpClient = httpClient; _config = config; @@ -90,6 +92,8 @@ namespace MediaBrowser.Server.Implementations.LiveTv.EmbyTV status.Tuners = list; status.Status = LiveTvServiceStatus.Ok; + status.Version = _appHpst.ApplicationVersion.ToString(); + status.IsVisible = false; return status; } diff --git a/MediaBrowser.Server.Implementations/LiveTv/Listings/SchedulesDirect.cs b/MediaBrowser.Server.Implementations/LiveTv/Listings/SchedulesDirect.cs new file mode 100644 index 0000000000..7070c5a5fd --- /dev/null +++ b/MediaBrowser.Server.Implementations/LiveTv/Listings/SchedulesDirect.cs @@ -0,0 +1,16 @@ +using MediaBrowser.Controller.LiveTv; +using System; +using System.Collections.Generic; +using System.Threading; +using System.Threading.Tasks; + +namespace MediaBrowser.Server.Implementations.LiveTv.Listings +{ + public class SchedulesDirect : IListingsProvider + { + public Task> GetProgramsAsync(ChannelInfo channel, DateTime startDateUtc, DateTime endDateUtc, CancellationToken cancellationToken) + { + throw new NotImplementedException(); + } + } +} diff --git a/MediaBrowser.Server.Implementations/LiveTv/LiveTvManager.cs b/MediaBrowser.Server.Implementations/LiveTv/LiveTvManager.cs index 80ec2a0365..05bc276b86 100644 --- a/MediaBrowser.Server.Implementations/LiveTv/LiveTvManager.cs +++ b/MediaBrowser.Server.Implementations/LiveTv/LiveTvManager.cs @@ -2057,6 +2057,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv info.Version = statusInfo.Version; info.HasUpdateAvailable = statusInfo.HasUpdateAvailable; info.HomePageUrl = service.HomePageUrl; + info.IsVisible = statusInfo.IsVisible; info.Tuners = statusInfo.Tuners.Select(i => { diff --git a/MediaBrowser.Server.Implementations/LiveTv/TunerHosts/HdHomerun.cs b/MediaBrowser.Server.Implementations/LiveTv/TunerHosts/HdHomerun.cs index cadbe7bc3b..b5b588682a 100644 --- a/MediaBrowser.Server.Implementations/LiveTv/TunerHosts/HdHomerun.cs +++ b/MediaBrowser.Server.Implementations/LiveTv/TunerHosts/HdHomerun.cs @@ -3,6 +3,7 @@ using MediaBrowser.Common.Net; using MediaBrowser.Controller.LiveTv; using MediaBrowser.Model.Dto; using MediaBrowser.Model.Entities; +using MediaBrowser.Model.Extensions; using MediaBrowser.Model.LiveTv; using MediaBrowser.Model.Logging; using MediaBrowser.Model.MediaInfo; @@ -14,6 +15,7 @@ using System.IO; using System.Linq; using System.Threading; using System.Threading.Tasks; +using MediaBrowser.Server.Implementations.LiveTv.EmbyTV; namespace MediaBrowser.Server.Implementations.LiveTv.TunerHosts { @@ -70,12 +72,31 @@ namespace MediaBrowser.Server.Implementations.LiveTv.TunerHosts public async Task> GetTunerInfos(TunerHostInfo info, CancellationToken cancellationToken) { - var httpOptions = new HttpRequestOptions() + string model = null; + + using (var stream = await _httpClient.Get(new HttpRequestOptions() + { + Url = string.Format("{0}/", GetApiUrl(info)), + CancellationToken = cancellationToken + })) + { + using (var sr = new StreamReader(stream, System.Text.Encoding.UTF8)) + { + while (!sr.EndOfStream) + { + string line = StripXML(sr.ReadLine()); + if (line.StartsWith("Model:")) { model = line.Replace("Model: ", ""); } + //if (line.StartsWith("Device ID:")) { deviceID = line.Replace("Device ID: ", ""); } + //if (line.StartsWith("Firmware:")) { firmware = line.Replace("Firmware: ", ""); } + } + } + } + + using (var stream = await _httpClient.Get(new HttpRequestOptions() { Url = string.Format("{0}/tuners.html", GetApiUrl(info)), CancellationToken = cancellationToken - }; - using (var stream = await _httpClient.Get(httpOptions)) + })) { var tuners = new List(); using (var sr = new StreamReader(stream, System.Text.Encoding.UTF8)) @@ -93,7 +114,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv.TunerHosts tuners.Add(new LiveTvTunerInfo() { Name = name, - SourceType = Name, + SourceType = string.IsNullOrWhiteSpace(model) ? Name : model, ProgramName = currentChannel, Status = status }); diff --git a/MediaBrowser.Server.Implementations/Localization/JavaScript/javascript.json b/MediaBrowser.Server.Implementations/Localization/JavaScript/javascript.json index 2d56e96567..89ff3a9844 100644 --- a/MediaBrowser.Server.Implementations/Localization/JavaScript/javascript.json +++ b/MediaBrowser.Server.Implementations/Localization/JavaScript/javascript.json @@ -816,5 +816,6 @@ "ButtonShareHelp": "Share a web page containing media information with social media. Media files are never shared publicly.", "ButtonShare": "Share", "HeaderConfirm": "Confirm", - "ButtonAdvancedRefresh": "Advanced Refresh" + "ButtonAdvancedRefresh": "Advanced Refresh", + "MessageConfirmDeleteTunerDevice": "Are you sure you wish to delete this device?" } diff --git a/MediaBrowser.Server.Implementations/Localization/Server/server.json b/MediaBrowser.Server.Implementations/Localization/Server/server.json index 5a1d9f29ed..b6c1321fa5 100644 --- a/MediaBrowser.Server.Implementations/Localization/Server/server.json +++ b/MediaBrowser.Server.Implementations/Localization/Server/server.json @@ -1473,5 +1473,12 @@ "HeaderShortOverview": "Short Overview", "HeaderType": "Type", "HeaderSeverity": "Severity", - "OptionReportActivities": "Activities Log" + "OptionReportActivities": "Activities Log", + "HeaderTunerDevices": "Tuner Devices", + "ButtonAddDevice": "Add Device", + "HeaderAddDevice": "Add Device", + "HeaderExternalServices": "External Services", + "LabelIpAddressPath": "IP Address / Path:", + "TabExternalServices": "External Services", + "TabTuners": "Tuners" } diff --git a/MediaBrowser.Server.Implementations/MediaBrowser.Server.Implementations.csproj b/MediaBrowser.Server.Implementations/MediaBrowser.Server.Implementations.csproj index bc1d07426c..dc149318b8 100644 --- a/MediaBrowser.Server.Implementations/MediaBrowser.Server.Implementations.csproj +++ b/MediaBrowser.Server.Implementations/MediaBrowser.Server.Implementations.csproj @@ -221,6 +221,7 @@ + -- cgit v1.2.3 From 7300a475d1892c553bb0a3a5fc21cc32d09b4950 Mon Sep 17 00:00:00 2001 From: Luke Pulverenti Date: Thu, 23 Jul 2015 01:25:55 -0400 Subject: update live tv setup --- .../HttpClientManager/HttpClientManager.cs | 3 + .../LiveTv/IListingsProvider.cs | 7 +- MediaBrowser.Model/LiveTv/LiveTvOptions.cs | 14 +- .../Channels/ChannelDownloadScheduledTask.cs | 8 +- .../Channels/ChannelManager.cs | 93 +-- .../EntryPoints/UsageReporter.cs | 2 + .../LiveTv/EmbyTV/EmbyTV.cs | 51 +- .../LiveTv/Listings/SchedulesDirect.cs | 836 ++++++++++++++++++++- .../Localization/JavaScript/javascript.json | 5 +- .../Localization/Server/server.json | 7 +- .../MediaBrowser.WebDashboard.csproj | 6 + 11 files changed, 923 insertions(+), 109 deletions(-) (limited to 'MediaBrowser.Model/LiveTv') diff --git a/MediaBrowser.Common.Implementations/HttpClientManager/HttpClientManager.cs b/MediaBrowser.Common.Implementations/HttpClientManager/HttpClientManager.cs index 7ca6f43d6c..18441161f0 100644 --- a/MediaBrowser.Common.Implementations/HttpClientManager/HttpClientManager.cs +++ b/MediaBrowser.Common.Implementations/HttpClientManager/HttpClientManager.cs @@ -68,6 +68,9 @@ namespace MediaBrowser.Common.Implementations.HttpClientManager // http://stackoverflow.com/questions/566437/http-post-returns-the-error-417-expectation-failed-c ServicePointManager.Expect100Continue = false; + + // Trakt requests sometimes fail without this + ServicePointManager.SecurityProtocol = SecurityProtocolType.Ssl3 | SecurityProtocolType.Tls; } /// diff --git a/MediaBrowser.Controller/LiveTv/IListingsProvider.cs b/MediaBrowser.Controller/LiveTv/IListingsProvider.cs index 75ca7e0dcc..beaa4eeafa 100644 --- a/MediaBrowser.Controller/LiveTv/IListingsProvider.cs +++ b/MediaBrowser.Controller/LiveTv/IListingsProvider.cs @@ -1,4 +1,5 @@ -using System; +using MediaBrowser.Model.LiveTv; +using System; using System.Collections.Generic; using System.Threading; using System.Threading.Tasks; @@ -7,6 +8,8 @@ namespace MediaBrowser.Controller.LiveTv { public interface IListingsProvider { - Task> GetProgramsAsync(ChannelInfo channel, DateTime startDateUtc, DateTime endDateUtc, CancellationToken cancellationToken); + string Name { get; } + Task> GetProgramsAsync(ListingsProviderInfo info, ChannelInfo channel, DateTime startDateUtc, DateTime endDateUtc, CancellationToken cancellationToken); + Task AddMetadata(ListingsProviderInfo info, List channels, CancellationToken cancellationToken); } } diff --git a/MediaBrowser.Model/LiveTv/LiveTvOptions.cs b/MediaBrowser.Model/LiveTv/LiveTvOptions.cs index 2ca7397c1e..c78fbe630a 100644 --- a/MediaBrowser.Model/LiveTv/LiveTvOptions.cs +++ b/MediaBrowser.Model/LiveTv/LiveTvOptions.cs @@ -6,13 +6,16 @@ namespace MediaBrowser.Model.LiveTv { public int? GuideDays { get; set; } public bool EnableMovieProviders { get; set; } - public List TunerHosts { get; set; } public string RecordingPath { get; set; } + public List TunerHosts { get; set; } + public List ListingProviders { get; set; } + public LiveTvOptions() { EnableMovieProviders = true; TunerHosts = new List(); + ListingProviders = new List(); } } @@ -22,4 +25,13 @@ namespace MediaBrowser.Model.LiveTv public string Url { get; set; } public string Type { get; set; } } + + public class ListingsProviderInfo + { + public string ProviderName { get; set; } + public string Username { get; set; } + public string Password { get; set; } + public string ZipCode { get; set; } + public string ListingsId { get; set; } + } } \ No newline at end of file diff --git a/MediaBrowser.Server.Implementations/Channels/ChannelDownloadScheduledTask.cs b/MediaBrowser.Server.Implementations/Channels/ChannelDownloadScheduledTask.cs index 18711c61e2..337e26e8d2 100644 --- a/MediaBrowser.Server.Implementations/Channels/ChannelDownloadScheduledTask.cs +++ b/MediaBrowser.Server.Implementations/Channels/ChannelDownloadScheduledTask.cs @@ -1,8 +1,6 @@ using MediaBrowser.Common.IO; -using MediaBrowser.Common.Net; using MediaBrowser.Common.Progress; using MediaBrowser.Common.ScheduledTasks; -using MediaBrowser.Common.Security; using MediaBrowser.Controller.Channels; using MediaBrowser.Controller.Configuration; using MediaBrowser.Controller.Entities; @@ -29,22 +27,18 @@ namespace MediaBrowser.Server.Implementations.Channels private readonly IChannelManager _manager; private readonly IServerConfigurationManager _config; private readonly ILogger _logger; - private readonly IHttpClient _httpClient; private readonly IFileSystem _fileSystem; private readonly ILibraryManager _libraryManager; private readonly IUserManager _userManager; - private readonly ISecurityManager _security; - public ChannelDownloadScheduledTask(IChannelManager manager, IServerConfigurationManager config, ILogger logger, IHttpClient httpClient, IFileSystem fileSystem, ILibraryManager libraryManager, IUserManager userManager, ISecurityManager security) + public ChannelDownloadScheduledTask(IChannelManager manager, IServerConfigurationManager config, ILogger logger, IFileSystem fileSystem, ILibraryManager libraryManager, IUserManager userManager) { _manager = manager; _config = config; _logger = logger; - _httpClient = httpClient; _fileSystem = fileSystem; _libraryManager = libraryManager; _userManager = userManager; - _security = security; } public string Name diff --git a/MediaBrowser.Server.Implementations/Channels/ChannelManager.cs b/MediaBrowser.Server.Implementations/Channels/ChannelManager.cs index 0cd4b0a5c9..3e58e3bd56 100644 --- a/MediaBrowser.Server.Implementations/Channels/ChannelManager.cs +++ b/MediaBrowser.Server.Implementations/Channels/ChannelManager.cs @@ -23,7 +23,6 @@ using System.Collections.Generic; using System.IO; using System.Linq; using System.Net; -using System.Text; using System.Threading; using System.Threading.Tasks; @@ -255,7 +254,7 @@ namespace MediaBrowser.Server.Implementations.Channels sources.InsertRange(0, cachedVersions); } - return sources.Where(IsValidMediaSource); + return sources; } public async Task> GetDynamicMediaSources(IChannelMediaItem item, CancellationToken cancellationToken) @@ -279,7 +278,6 @@ namespace MediaBrowser.Server.Implementations.Channels var list = SortMediaInfoResults(results) .Select(i => GetMediaSource(item, i)) - .Where(IsValidMediaSource) .ToList(); var cachedVersions = GetCachedChannelItemMediaSources(item); @@ -1424,18 +1422,8 @@ namespace MediaBrowser.Server.Implementations.Channels foreach (var source in list) { - try - { - await TryDownloadChannelItem(source, item, destination, progress, cancellationToken).ConfigureAwait(false); - return; - } - catch (HttpException ex) - { - if (ex.StatusCode.HasValue && ex.StatusCode.Value == HttpStatusCode.NotFound) - { - MarkBadMediaSource(source); - } - } + await TryDownloadChannelItem(source, item, destination, progress, cancellationToken).ConfigureAwait(false); + return; } } @@ -1525,81 +1513,6 @@ namespace MediaBrowser.Server.Implementations.Channels } } - private readonly ReaderWriterLockSlim _mediaSourceHistoryLock = new ReaderWriterLockSlim(); - private bool IsValidMediaSource(MediaSourceInfo source) - { - if (source.Protocol == MediaProtocol.Http) - { - return !GetBadMediaSourceHistory().Contains(source.Path, StringComparer.OrdinalIgnoreCase); - } - return true; - } - - private void MarkBadMediaSource(MediaSourceInfo source) - { - var list = GetBadMediaSourceHistory(); - list.Add(source.Path); - - var path = GetMediaSourceHistoryPath(); - - Directory.CreateDirectory(Path.GetDirectoryName(path)); - - if (_mediaSourceHistoryLock.TryEnterWriteLock(TimeSpan.FromSeconds(5))) - { - try - { - File.WriteAllLines(path, list.ToArray(), Encoding.UTF8); - } - catch (Exception ex) - { - _logger.ErrorException("Error saving file", ex); - } - finally - { - _mediaSourceHistoryLock.ExitWriteLock(); - } - } - } - - private ConcurrentBag _badMediaSources = null; - private ConcurrentBag GetBadMediaSourceHistory() - { - if (_badMediaSources == null) - { - var path = GetMediaSourceHistoryPath(); - - if (_mediaSourceHistoryLock.TryEnterReadLock(TimeSpan.FromSeconds(1))) - { - if (_badMediaSources == null) - { - try - { - _badMediaSources = new ConcurrentBag(File.ReadAllLines(path, Encoding.UTF8)); - } - catch (IOException) - { - _badMediaSources = new ConcurrentBag(); - } - catch (Exception ex) - { - _logger.ErrorException("Error reading file", ex); - _badMediaSources = new ConcurrentBag(); - } - finally - { - _mediaSourceHistoryLock.ExitReadLock(); - } - } - } - } - return _badMediaSources; - } - - private string GetMediaSourceHistoryPath() - { - return Path.Combine(_config.ApplicationPaths.DataPath, "channels", "failures.txt"); - } - private void IncrementDownloadCount(string key, int? limit) { if (!limit.HasValue) diff --git a/MediaBrowser.Server.Implementations/EntryPoints/UsageReporter.cs b/MediaBrowser.Server.Implementations/EntryPoints/UsageReporter.cs index 315493e0da..77dd54a80b 100644 --- a/MediaBrowser.Server.Implementations/EntryPoints/UsageReporter.cs +++ b/MediaBrowser.Server.Implementations/EntryPoints/UsageReporter.cs @@ -46,6 +46,8 @@ namespace MediaBrowser.Server.Implementations.EntryPoints data["guests"] = users.Count(i => i.ConnectLinkType.HasValue && i.ConnectLinkType.Value == UserLinkType.Guest).ToString(CultureInfo.InvariantCulture); data["linkedusers"] = users.Count(i => i.ConnectLinkType.HasValue && i.ConnectLinkType.Value == UserLinkType.LinkedUser).ToString(CultureInfo.InvariantCulture); + data["plugins"] = string.Join(",", _applicationHost.Plugins.Select(i => i.Id).ToArray()); + return _httpClient.Post(MbAdminUrl + "service/registration/ping", data, cancellationToken); } diff --git a/MediaBrowser.Server.Implementations/LiveTv/EmbyTV/EmbyTV.cs b/MediaBrowser.Server.Implementations/LiveTv/EmbyTV/EmbyTV.cs index b71d62f433..26e0709215 100644 --- a/MediaBrowser.Server.Implementations/LiveTv/EmbyTV/EmbyTV.cs +++ b/MediaBrowser.Server.Implementations/LiveTv/EmbyTV/EmbyTV.cs @@ -26,11 +26,13 @@ namespace MediaBrowser.Server.Implementations.LiveTv.EmbyTV private readonly IConfigurationManager _config; private readonly IJsonSerializer _jsonSerializer; - private readonly List _tunerHosts = new List(); private readonly ItemDataProvider _recordingProvider; private readonly ItemDataProvider _seriesTimerProvider; private readonly TimerManager _timerProvider; + private readonly List _tunerHosts = new List(); + private readonly List _listingProviders = new List(); + public EmbyTV(IApplicationHost appHost, ILogger logger, IJsonSerializer jsonSerializer, IHttpClient httpClient, IConfigurationManager config) { _appHpst = appHost; @@ -39,6 +41,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv.EmbyTV _config = config; _jsonSerializer = jsonSerializer; _tunerHosts.AddRange(appHost.GetExports()); + _listingProviders.AddRange(appHost.GetExports()); _recordingProvider = new ItemDataProvider(jsonSerializer, _logger, Path.Combine(DataPath, "recordings"), (r1, r2) => string.Equals(r1.Id, r2.Id, StringComparison.OrdinalIgnoreCase)); _seriesTimerProvider = new SeriesTimerManager(jsonSerializer, _logger, Path.Combine(DataPath, "seriestimers")); @@ -118,6 +121,14 @@ namespace MediaBrowser.Server.Implementations.LiveTv.EmbyTV } } + if (list.Count > 0) + { + foreach (var provider in GetListingProviders()) + { + await provider.Item1.AddMetadata(provider.Item2, list, cancellationToken).ConfigureAwait(false); + } + } + return list; } @@ -246,9 +257,43 @@ namespace MediaBrowser.Server.Implementations.LiveTv.EmbyTV return Task.FromResult((IEnumerable)_seriesTimerProvider.GetAll()); } - public Task> GetProgramsAsync(string channelId, DateTime startDateUtc, DateTime endDateUtc, CancellationToken cancellationToken) + public async Task> GetProgramsAsync(string channelId, DateTime startDateUtc, DateTime endDateUtc, CancellationToken cancellationToken) { - throw new NotImplementedException(); + var allChannels = await GetChannelsAsync(cancellationToken).ConfigureAwait(false); + var channelInfo = allChannels.FirstOrDefault(i => string.Equals(channelId, i.Id, StringComparison.OrdinalIgnoreCase)); + + if (channelInfo == null) + { + _logger.Debug("Returning empty program list because channel was not found."); + return new List(); + } + + foreach (var provider in GetListingProviders()) + { + var programs = await provider.Item1.GetProgramsAsync(provider.Item2, channelInfo, startDateUtc, endDateUtc, cancellationToken) + .ConfigureAwait(false); + var list = programs.ToList(); + + if (list.Count > 0) + { + return list; + } + } + + return new List(); + } + + private List> GetListingProviders() + { + return GetConfiguration().ListingProviders + .Select(i => + { + var provider = _listingProviders.FirstOrDefault(l => string.Equals(l.Name, i.ProviderName, StringComparison.OrdinalIgnoreCase)); + + return provider == null ? null : new Tuple(provider, i); + }) + .Where(i => i != null) + .ToList(); } public Task GetRecordingStream(string recordingId, string streamId, CancellationToken cancellationToken) diff --git a/MediaBrowser.Server.Implementations/LiveTv/Listings/SchedulesDirect.cs b/MediaBrowser.Server.Implementations/LiveTv/Listings/SchedulesDirect.cs index 7070c5a5fd..3b7564983e 100644 --- a/MediaBrowser.Server.Implementations/LiveTv/Listings/SchedulesDirect.cs +++ b/MediaBrowser.Server.Implementations/LiveTv/Listings/SchedulesDirect.cs @@ -1,6 +1,15 @@ -using MediaBrowser.Controller.LiveTv; +using MediaBrowser.Common.Net; +using MediaBrowser.Controller.LiveTv; +using MediaBrowser.Model.Dto; +using MediaBrowser.Model.LiveTv; +using MediaBrowser.Model.Logging; +using MediaBrowser.Model.Serialization; using System; +using System.Collections.Concurrent; using System.Collections.Generic; +using System.Globalization; +using System.IO; +using System.Linq; using System.Threading; using System.Threading.Tasks; @@ -8,9 +17,830 @@ namespace MediaBrowser.Server.Implementations.LiveTv.Listings { public class SchedulesDirect : IListingsProvider { - public Task> GetProgramsAsync(ChannelInfo channel, DateTime startDateUtc, DateTime endDateUtc, CancellationToken cancellationToken) + private readonly ILogger _logger; + private readonly IJsonSerializer _jsonSerializer; + private readonly IHttpClient _httpClient; + private const string UserAgent = "EmbyTV"; + private readonly SemaphoreSlim _tokenSemaphore = new SemaphoreSlim(1, 1); + + private const string ApiUrl = "https://json.schedulesdirect.org/20141201"; + + private readonly ConcurrentDictionary _channelPair = + new ConcurrentDictionary(); + + public SchedulesDirect(ILogger logger, IJsonSerializer jsonSerializer, IHttpClient httpClient) + { + _logger = logger; + _jsonSerializer = jsonSerializer; + _httpClient = httpClient; + } + + public async Task> GetProgramsAsync(ListingsProviderInfo info, ChannelInfo channel, DateTime startDateUtc, DateTime endDateUtc, CancellationToken cancellationToken) + { + var channelNumber = channel.Number; + + List programsInfo = new List(); + + var token = await GetToken(info, cancellationToken); + + if (string.IsNullOrWhiteSpace(token)) + { + return programsInfo; + } + + if (string.IsNullOrWhiteSpace(info.ListingsId)) + { + return programsInfo; + } + + var httpOptions = new HttpRequestOptions() + { + Url = ApiUrl + "/schedules", + UserAgent = UserAgent, + CancellationToken = cancellationToken + }; + + httpOptions.RequestHeaders["token"] = token; + + List dates = new List(); + int numberOfDay = 0; + DateTime lastEntry = startDateUtc; + while (lastEntry != endDateUtc) + { + lastEntry = startDateUtc.AddDays(numberOfDay); + dates.Add(lastEntry.ToString("yyyy-MM-dd")); + numberOfDay++; + } + + ScheduleDirect.Station station = null; + + if (!_channelPair.TryGetValue("", out station)) + { + return programsInfo; + } + string stationID = station.stationID; + + _logger.Info("Channel Station ID is: " + stationID); + List requestList = + new List() + { + new ScheduleDirect.RequestScheduleForChannel() + { + stationID = stationID, + date = dates + } + }; + + var requestString = _jsonSerializer.SerializeToString(requestList); + _logger.Debug("Request string for schedules is: " + requestString); + httpOptions.RequestContent = requestString; + using (var response = await _httpClient.Post(httpOptions)) + { + StreamReader reader = new StreamReader(response.Content); + string responseString = reader.ReadToEnd(); + var dailySchedules = _jsonSerializer.DeserializeFromString>(responseString); + _logger.Debug("Found " + dailySchedules.Count() + " programs on " + channelNumber + + " ScheduleDirect"); + + httpOptions = new HttpRequestOptions() + { + Url = ApiUrl + "/programs", + UserAgent = UserAgent, + CancellationToken = cancellationToken + }; + + httpOptions.RequestHeaders["token"] = token; + + List programsID = new List(); + programsID = dailySchedules.SelectMany(d => d.programs.Select(s => s.programID)).Distinct().ToList(); + var requestBody = "[\"" + string.Join("\", \"", programsID) + "\"]"; + httpOptions.RequestContent = requestBody; + + using (var innerResponse = await _httpClient.Post(httpOptions)) + { + StreamReader innerReader = new StreamReader(innerResponse.Content); + responseString = innerReader.ReadToEnd(); + var programDetails = + _jsonSerializer.DeserializeFromString>( + responseString); + var programDict = programDetails.ToDictionary(p => p.programID, y => y); + + var images = await GetImageForPrograms(programDetails.Where(p => p.hasImageArtwork).Select(p => p.programID).ToList(), cancellationToken); + + var schedules = dailySchedules.SelectMany(d => d.programs); + foreach (ScheduleDirect.Program schedule in schedules) + { + _logger.Debug("Proccesing Schedule for statio ID " + stationID + + " which corresponds to channel " + channelNumber + " and program id " + + schedule.programID + " which says it has images? " + + programDict[schedule.programID].hasImageArtwork); + + var imageIndex = images.FindIndex(i => i.programID == schedule.programID.Substring(0, 10)); + if (imageIndex > -1) + { + programDict[schedule.programID].images = GetProgramLogo(ApiUrl, images[imageIndex]); + } + + programsInfo.Add(GetProgram(channelNumber, schedule, programDict[schedule.programID])); + } + _logger.Info("Finished with EPGData"); + } + } + + return programsInfo; + } + + public async Task AddMetadata(ListingsProviderInfo info, List channels, + CancellationToken cancellationToken) + { + var token = await GetToken(info, cancellationToken); + + _channelPair.Clear(); + + if (!String.IsNullOrWhiteSpace(token) && !String.IsNullOrWhiteSpace(info.ListingsId)) + { + var httpOptions = new HttpRequestOptions() + { + Url = ApiUrl + "/lineups/" + info.ListingsId, + UserAgent = UserAgent, + CancellationToken = cancellationToken + }; + + httpOptions.RequestHeaders["token"] = token; + + using (var response = await _httpClient.Get(httpOptions)) + { + var root = _jsonSerializer.DeserializeFromStream(response); + _logger.Info("Found " + root.map.Count() + " channels on the lineup on ScheduleDirect"); + _logger.Info("Mapping Stations to Channel"); + foreach (ScheduleDirect.Map map in root.map) + { + var channel = (map.channel ?? (map.atscMajor + "." + map.atscMinor)).TrimStart('0'); + _logger.Debug("Found channel: " + channel + " in Schedules Direct"); + var schChannel = root.stations.FirstOrDefault(item => item.stationID == map.stationID); + + if (!_channelPair.ContainsKey(channel) && channel != "0.0" && schChannel != null) + { + _channelPair.TryAdd(channel, schChannel); + } + } + _logger.Info("Added " + _channelPair.Count() + " channels to the dictionary"); + + foreach (ChannelInfo channel in channels) + { + // Helper.logger.Info("Modifyin channel " + channel.Number); + if (_channelPair.ContainsKey(channel.Number)) + { + string channelName; + if (_channelPair[channel.Number].logo != null) + { + channel.ImageUrl = _channelPair[channel.Number].logo.URL; + channel.HasImage = true; + } + if (_channelPair[channel.Number].affiliate != null) + { + channelName = _channelPair[channel.Number].affiliate; + } + else + { + channelName = _channelPair[channel.Number].name; + } + channel.Name = channelName; + } + else + { + _logger.Info("Schedules Direct doesnt have data for channel: " + channel.Number + " " + + channel.Name); + } + } + } + } + } + + private async Task GetLineup(string listingsId, string token, CancellationToken cancellationToken) + { + var httpOptions = new HttpRequestOptions() + { + Url = ApiUrl + "/lineups/" + listingsId, + UserAgent = UserAgent, + CancellationToken = cancellationToken + }; + + httpOptions.RequestHeaders["token"] = token; + + using (var response = await _httpClient.Get(httpOptions)) + { + var root = _jsonSerializer.DeserializeFromStream(response); + _logger.Info("Found " + root.map.Count() + " channels on the lineup on ScheduleDirect"); + _logger.Info("Mapping Stations to Channel"); + foreach (ScheduleDirect.Map map in root.map) + { + var channel = (map.channel ?? (map.atscMajor + "." + map.atscMinor)).TrimStart('0'); + _logger.Debug("Found channel: " + channel + " in Schedules Direct"); + + var schChannel = root.stations.FirstOrDefault(item => item.stationID == map.stationID); + + if (!_channelPair.ContainsKey(channel) && channel != "0.0" && schChannel != null) + { + _channelPair.TryAdd(channel, schChannel); + } + } + + return root; + } + } + + private ProgramInfo GetProgram(string channel, ScheduleDirect.Program programInfo, + ScheduleDirect.ProgramDetails details) + { + _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); + ProgramAudio audioType = ProgramAudio.Stereo; + bool hdtv = false; + bool repeat = (programInfo.@new == null); + string newID = programInfo.programID + "T" + startAt.Ticks + "C" + channel; + + + if (programInfo.audioProperties != null) + { + if (programInfo.audioProperties.Exists(item => item == "stereo")) + { + audioType = ProgramAudio.Stereo; + } + else + { + audioType = ProgramAudio.Mono; + } + } + + if ((programInfo.videoProperties != null)) + { + hdtv = programInfo.videoProperties.Exists(item => item == "hdtv"); + } + + string desc = ""; + if (details.descriptions != null) + { + if (details.descriptions.description1000 != null) + { + desc = details.descriptions.description1000[0].description; + } + else if (details.descriptions.description100 != null) + { + desc = details.descriptions.description100[0].description; + } + } + ScheduleDirect.Gracenote gracenote; + string EpisodeTitle = ""; + if (details.metadata != null) + { + gracenote = details.metadata.Find(x => x.Gracenote != null).Gracenote; + if ((details.showType ?? "No ShowType") == "Series") + { + EpisodeTitle = "Season: " + gracenote.season + " Episode: " + gracenote.episode; + } + } + if (details.episodeTitle150 != null) + { + EpisodeTitle = EpisodeTitle + " " + details.episodeTitle150; + } + bool hasImage = false; + var imageLink = ""; + + if (details.hasImageArtwork) + { + imageLink = details.images; + } + + + var info = new ProgramInfo + { + ChannelId = channel, + Id = newID, + Overview = desc, + StartDate = startAt, + EndDate = endAt, + Genres = new List() { "N/A" }, + Name = details.titles[0].title120 ?? "Unkown", + OfficialRating = "0", + CommunityRating = null, + EpisodeTitle = EpisodeTitle, + Audio = audioType, + IsHD = hdtv, + IsRepeat = repeat, + IsSeries = + ((details.showType ?? "No ShowType") == "Series") || + (details.showType ?? "No ShowType") == "Miniseries", + ImageUrl = imageLink, + HasImage = details.hasImageArtwork, + IsNews = false, + IsKids = false, + IsSports = + ((details.showType ?? "No ShowType") == "Sports non-event") || + (details.showType ?? "No ShowType") == "Sports event", + IsLive = false, + IsMovie = + (details.showType ?? "No ShowType") == "Feature Film" || + (details.showType ?? "No ShowType") == "TV Movie" || + (details.showType ?? "No ShowType") == "Short Film", + IsPremiere = false, + }; + //logger.Info("Done init"); + if (null != details.originalAirDate) + { + info.OriginalAirDate = DateTime.Parse(details.originalAirDate); + } + + if (details.genres != null) + { + info.Genres = details.genres.Where(g => !string.IsNullOrWhiteSpace(g)).ToList(); + info.IsNews = details.genres.Contains("news", StringComparer.OrdinalIgnoreCase); + info.IsKids = false; + } + return info; + } + + private string GetProgramLogo(string apiUrl, ScheduleDirect.ShowImages images) + { + string url = ""; + if (images.data != null) + { + var smallImages = images.data.Where(i => i.size == "Sm").ToList(); + if (smallImages.Any()) + { + images.data = smallImages; + } + var logoIndex = images.data.FindIndex(i => i.category == "Logo"); + if (logoIndex == -1) + { + logoIndex = 0; + } + if (images.data[logoIndex].uri.Contains("http")) + { + url = images.data[logoIndex].uri; + } + else + { + url = apiUrl + "/image/" + images.data[logoIndex].uri; + } + _logger.Debug("URL for image is : " + url); + } + return url; + } + + private async Task> GetImageForPrograms(List programIds, + CancellationToken cancellationToken) + { + var imageIdString = "["; + + programIds.ForEach(i => + { + if (!imageIdString.Contains(i.Substring(0, 10))) + { + imageIdString += "\"" + i.Substring(0, 10) + "\","; + } + ; + }); + imageIdString = imageIdString.TrimEnd(',') + "]"; + _logger.Debug("Json for show images = " + imageIdString); + var httpOptions = new HttpRequestOptions() + { + Url = ApiUrl + "/metadata/programs", + UserAgent = UserAgent, + CancellationToken = cancellationToken, + RequestContent = imageIdString + }; + List images; + using (var innerResponse2 = await _httpClient.Post(httpOptions)) + { + images = _jsonSerializer.DeserializeFromStream>( + innerResponse2.Content); + } + + return images; + } + + public async Task> GetHeadends(ListingsProviderInfo info, CancellationToken cancellationToken) + { + var token = await GetToken(info, cancellationToken); + + var lineups = new List(); + + if (string.IsNullOrWhiteSpace(token)) + { + return lineups; + } + + _logger.Info("Headends on account "); + + var options = new HttpRequestOptions() + { + Url = ApiUrl + "/headends?country=USA&postalcode=" + info.ZipCode, + UserAgent = UserAgent, + CancellationToken = cancellationToken + }; + + options.RequestHeaders["token"] = token; + + try + { + using (Stream responce = await _httpClient.Get(options).ConfigureAwait(false)) + { + var root = _jsonSerializer.DeserializeFromStream>(responce); + _logger.Info("Lineups on account "); + if (root != null) + { + foreach (ScheduleDirect.Headends headend in root) + { + _logger.Info("Headend: " + headend.headend); + foreach (ScheduleDirect.Lineup lineup in headend.lineups) + { + _logger.Info("Headend: " + lineup.uri.Substring(18)); + lineups.Add(new NameIdPair() + { + Name = string.IsNullOrWhiteSpace(lineup.name) ? lineup.lineup : lineup.name, + Id = lineup.uri.Substring(18) + }); + } + } + } + else + { + _logger.Info("No lineups on account"); + } + } + } + catch (Exception ex) + { + _logger.Error("Error getting headends", ex); + } + + return lineups; + } + + private readonly ConcurrentDictionary _tokens = new ConcurrentDictionary(); + + private async Task GetToken(ListingsProviderInfo info, CancellationToken cancellationToken) + { + await _tokenSemaphore.WaitAsync(cancellationToken).ConfigureAwait(false); + try + { + var username = info.Username; + + // Reset the token if there's no username + if (string.IsNullOrWhiteSpace(username)) + { + return null; + } + + var password = info.Password; + if (string.IsNullOrWhiteSpace(password)) + { + return null; + } + + NameValuePair savedToken = null; + if (!_tokens.TryGetValue(username, out savedToken)) + { + savedToken = new NameValuePair(); + _tokens.TryAdd(username, savedToken); + } + + if (!string.IsNullOrWhiteSpace(savedToken.Name) && !string.IsNullOrWhiteSpace(savedToken.Value)) + { + long ticks; + if (long.TryParse(savedToken.Value, NumberStyles.Any, CultureInfo.InvariantCulture, out ticks)) + { + // If it's under 24 hours old we can still use it + if ((DateTime.UtcNow.Ticks - ticks) < TimeSpan.FromHours(24).Ticks) + { + return savedToken.Name; + } + } + } + + var result = await GetTokenInternal(username, password, cancellationToken).ConfigureAwait(false); + savedToken.Name = result; + savedToken.Value = DateTime.UtcNow.Ticks.ToString(CultureInfo.InvariantCulture); + return result; + } + finally + { + _tokenSemaphore.Release(); + } + } + + private async Task GetTokenInternal(string username, string password, + CancellationToken cancellationToken) { - throw new NotImplementedException(); + var httpOptions = new HttpRequestOptions() + { + Url = ApiUrl + "/token", + UserAgent = UserAgent, + RequestContent = "{\"username\":\"" + username + "\",\"password\":\"" + password + "\"}", + CancellationToken = cancellationToken + }; + //_logger.Info("Obtaining token from Schedules Direct from addres: " + httpOptions.Url + " with body " + + // httpOptions.RequestContent); + + using (var responce = await _httpClient.Post(httpOptions)) + { + var root = _jsonSerializer.DeserializeFromStream(responce.Content); + if (root.message == "OK") + { + _logger.Info("Authenticated with Schedules Direct token: " + root.token); + return root.token; + } + + throw new ApplicationException("Could not authenticate with Schedules Direct Error: " + root.message); + } + } + + public string Name + { + get { return "Schedules Direct"; } + } + + public class ScheduleDirect + { + public class Token + { + public int code { get; set; } + public string message { get; set; } + public string serverID { get; set; } + public string token { get; set; } + } + public class Lineup + { + public string lineup { get; set; } + public string name { get; set; } + public string transport { get; set; } + public string location { get; set; } + public string uri { get; set; } + } + + public class Lineups + { + public int code { get; set; } + public string serverID { get; set; } + public string datetime { get; set; } + public List lineups { get; set; } + } + + + public class Headends + { + public string headend { get; set; } + public string transport { get; set; } + public string location { get; set; } + public List lineups { get; set; } + } + + + + public class Map + { + public string stationID { get; set; } + public string channel { get; set; } + public int uhfVhf { get; set; } + public int atscMajor { get; set; } + public int atscMinor { get; set; } + } + + public class Broadcaster + { + public string city { get; set; } + public string state { get; set; } + public string postalcode { get; set; } + public string country { get; set; } + } + + public class Logo + { + public string URL { get; set; } + public int height { get; set; } + public int width { get; set; } + public string md5 { get; set; } + } + + public class Station + { + public string stationID { get; set; } + public string name { get; set; } + public string callsign { get; set; } + public List broadcastLanguage { get; set; } + public List descriptionLanguage { get; set; } + public Broadcaster broadcaster { get; set; } + public string affiliate { get; set; } + public Logo logo { get; set; } + public bool? isCommercialFree { get; set; } + } + + public class Metadata + { + public string lineup { get; set; } + public string modified { get; set; } + public string transport { get; set; } + } + + public class Channel + { + public List map { get; set; } + public List stations { get; set; } + public Metadata metadata { get; set; } + } + + public class RequestScheduleForChannel + { + public string stationID { get; set; } + public List date { get; set; } + } + + + + + public class Rating + { + public string body { get; set; } + public string code { get; set; } + } + + public class Multipart + { + public int partNumber { get; set; } + public int totalParts { get; set; } + } + + public class Program + { + public string programID { get; set; } + public string airDateTime { get; set; } + public int duration { get; set; } + public string md5 { get; set; } + public List audioProperties { get; set; } + public List videoProperties { get; set; } + public List ratings { get; set; } + public bool? @new { get; set; } + public Multipart multipart { get; set; } + } + + + + public class MetadataSchedule + { + public string modified { get; set; } + public string md5 { get; set; } + public string startDate { get; set; } + public string endDate { get; set; } + public int days { get; set; } + } + + public class Day + { + public string stationID { get; set; } + public List programs { get; set; } + public MetadataSchedule metadata { get; set; } + } + + // + public class Title + { + public string title120 { get; set; } + } + + public class EventDetails + { + public string subType { get; set; } + } + + public class Description100 + { + public string descriptionLanguage { get; set; } + public string description { get; set; } + } + + public class Description1000 + { + public string descriptionLanguage { get; set; } + public string description { get; set; } + } + + public class DescriptionsProgram + { + public List description100 { get; set; } + public List description1000 { get; set; } + } + + public class Gracenote + { + public int season { get; set; } + public int episode { get; set; } + } + + public class MetadataPrograms + { + public Gracenote Gracenote { get; set; } + } + + public class ContentRating + { + public string body { get; set; } + public string code { get; set; } + } + + public class Cast + { + public string billingOrder { get; set; } + public string role { get; set; } + public string nameId { get; set; } + public string personId { get; set; } + public string name { get; set; } + public string characterName { get; set; } + } + + public class Crew + { + public string billingOrder { get; set; } + public string role { get; set; } + public string nameId { get; set; } + public string personId { get; set; } + public string name { get; set; } + } + + public class QualityRating + { + public string ratingsBody { get; set; } + public string rating { get; set; } + public string minRating { get; set; } + public string maxRating { get; set; } + public string increment { get; set; } + } + + public class Movie + { + public string year { get; set; } + public int duration { get; set; } + public List qualityRating { get; set; } + } + + public class Recommendation + { + public string programID { get; set; } + public string title120 { get; set; } + } + + public class ProgramDetails + { + public string programID { get; set; } + public List titles { get; set; } + public EventDetails eventDetails { get; set; } + public DescriptionsProgram descriptions { get; set; } + public string originalAirDate { get; set; } + public List<string> genres { get; set; } + public string episodeTitle150 { get; set; } + public List<MetadataPrograms> metadata { get; set; } + public List<ContentRating> contentRating { get; set; } + public List<Cast> cast { get; set; } + public List<Crew> crew { get; set; } + public string showType { get; set; } + public bool hasImageArtwork { get; set; } + public string images { get; set; } + public string imageID { get; set; } + public string md5 { get; set; } + public List<string> contentAdvisory { get; set; } + public Movie movie { get; set; } + public List<Recommendation> recommendations { get; set; } + } + + public class Caption + { + public string content { get; set; } + public string lang { get; set; } + } + + public class ImageData + { + public string width { get; set; } + public string height { get; set; } + public string uri { get; set; } + public string size { get; set; } + public string aspect { get; set; } + public string category { get; set; } + public string text { get; set; } + public string primary { get; set; } + public string tier { get; set; } + public Caption caption { get; set; } + } + + public class ShowImages + { + public string programID { get; set; } + public List<ImageData> data { get; set; } + } + } + } } diff --git a/MediaBrowser.Server.Implementations/Localization/JavaScript/javascript.json b/MediaBrowser.Server.Implementations/Localization/JavaScript/javascript.json index 89ff3a9844..d2b998ae8e 100644 --- a/MediaBrowser.Server.Implementations/Localization/JavaScript/javascript.json +++ b/MediaBrowser.Server.Implementations/Localization/JavaScript/javascript.json @@ -817,5 +817,8 @@ "ButtonShare": "Share", "HeaderConfirm": "Confirm", "ButtonAdvancedRefresh": "Advanced Refresh", - "MessageConfirmDeleteTunerDevice": "Are you sure you wish to delete this device?" + "MessageConfirmDeleteTunerDevice": "Are you sure you wish to delete this device?", + "MessageConfirmDeleteGuideProvider": "Are you sure you wish to delete this guide provider?", + "HeaderDeleteProvider": "Delete Provider", + "HeaderAddProvider": "Add Provider" } diff --git a/MediaBrowser.Server.Implementations/Localization/Server/server.json b/MediaBrowser.Server.Implementations/Localization/Server/server.json index b6c1321fa5..83c2ccf5d6 100644 --- a/MediaBrowser.Server.Implementations/Localization/Server/server.json +++ b/MediaBrowser.Server.Implementations/Localization/Server/server.json @@ -695,7 +695,7 @@ "NotificationOptionNewLibraryContentMultiple": "New content added (multiple)", "NotificationOptionCameraImageUploaded": "Camera image uploaded", "NotificationOptionUserLockedOut": "User locked out", - "HeaderSendNotificationHelp": "By default, notifications are delivered to your dashboard inbox. Browse the plugin catalog to install additional notification options.", + "HeaderSendNotificationHelp": "Notifications are delivered to your Emby inbox. Additional options can be installed from the Services tab.", "NotificationOptionServerRestartRequired": "Server restart required", "LabelNotificationEnabled": "Enable this notification", "LabelMonitorUsers": "Monitor activity from:", @@ -1480,5 +1480,8 @@ "HeaderExternalServices": "External Services", "LabelIpAddressPath": "IP Address / Path:", "TabExternalServices": "External Services", - "TabTuners": "Tuners" + "TabTuners": "Tuners", + "HeaderGuideProviders": "Guide Providers", + "AddGuideProviderHelp": "Add a source for TV Guide information", + "LabelZipCode": "Zip Code" } diff --git a/MediaBrowser.WebDashboard/MediaBrowser.WebDashboard.csproj b/MediaBrowser.WebDashboard/MediaBrowser.WebDashboard.csproj index ef5bc71efd..1920a9ed79 100644 --- a/MediaBrowser.WebDashboard/MediaBrowser.WebDashboard.csproj +++ b/MediaBrowser.WebDashboard/MediaBrowser.WebDashboard.csproj @@ -183,6 +183,9 @@ <Content Include="dashboard-ui\livetvguide.html"> <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory> </Content> + <Content Include="dashboard-ui\livetvguidesettings.html"> + <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory> + </Content> <Content Include="dashboard-ui\livetvrecordings.html"> <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory> </Content> @@ -204,6 +207,9 @@ <Content Include="dashboard-ui\scripts\homeupcoming.js"> <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory> </Content> + <Content Include="dashboard-ui\scripts\livetvguidesettings.js"> + <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory> + </Content> <Content Include="dashboard-ui\scripts\mypreferenceshome.js"> <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory> </Content> -- cgit v1.2.3 From 3fda8ec5c264f077b625247ab29ce504be25774c Mon Sep 17 00:00:00 2001 From: Luke Pulverenti <luke.pulverenti@gmail.com> Date: Thu, 23 Jul 2015 09:23:22 -0400 Subject: update tuner setup --- MediaBrowser.Api/LiveTv/LiveTvService.cs | 56 +++++++++++-- .../LiveTv/IListingsProvider.cs | 6 +- MediaBrowser.Controller/LiveTv/ILiveTvManager.cs | 25 +++++- MediaBrowser.Controller/LiveTv/ITunerHost.cs | 6 ++ MediaBrowser.Model/LiveTv/LiveTvOptions.cs | 5 +- .../LiveTv/EmbyTV/EmbyTV.cs | 14 ++-- .../LiveTv/Listings/SchedulesDirect.cs | 73 +++++++++------- .../LiveTv/LiveTvManager.cs | 98 +++++++++++++++++++++- .../LiveTv/TunerHosts/HdHomerun.cs | 8 +- .../LiveTv/TunerHosts/M3UTunerHost.cs | 8 ++ .../Localization/JavaScript/javascript.json | 5 +- .../Localization/Server/server.json | 5 +- .../ApplicationHost.cs | 2 +- .../MediaBrowser.WebDashboard.csproj | 4 +- 14 files changed, 256 insertions(+), 59 deletions(-) (limited to 'MediaBrowser.Model/LiveTv') diff --git a/MediaBrowser.Api/LiveTv/LiveTvService.cs b/MediaBrowser.Api/LiveTv/LiveTvService.cs index 49ba001cef..f40048ce40 100644 --- a/MediaBrowser.Api/LiveTv/LiveTvService.cs +++ b/MediaBrowser.Api/LiveTv/LiveTvService.cs @@ -1,4 +1,5 @@ -using MediaBrowser.Common.Configuration; +using System.Collections.Generic; +using MediaBrowser.Common.Configuration; using MediaBrowser.Controller.Dto; using MediaBrowser.Controller.Library; using MediaBrowser.Controller.LiveTv; @@ -345,6 +346,31 @@ namespace MediaBrowser.Api.LiveTv public string Id { get; set; } } + [Route("/LiveTv/ListingProviders", "POST", Summary = "Adds a listing provider")] + [Authenticated] + public class AddListingProvider : ListingsProviderInfo, IReturn<ListingsProviderInfo> + { + } + + [Route("/LiveTv/ListingProviders", "DELETE", Summary = "Deletes a listing provider")] + [Authenticated] + public class DeleteListingProvider : IReturnVoid + { + [ApiMember(Name = "Id", Description = "Provider id", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "DELETE")] + public string Id { get; set; } + } + + [Route("/LiveTv/ListingProviders/Lineups", "GET", Summary = "Gets available lineups")] + [Authenticated] + public class GetLineups : IReturn<List<NameIdPair>> + { + [ApiMember(Name = "Id", Description = "Provider id", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET")] + public string Id { get; set; } + + [ApiMember(Name = "Location", Description = "Location", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET")] + public string Location { get; set; } + } + public class LiveTvService : BaseApiService { private readonly ILiveTvManager _liveTvManager; @@ -373,20 +399,27 @@ namespace MediaBrowser.Api.LiveTv } } - public void Post(AddTunerHost request) + public object Post(AddListingProvider request) + { + var result = _liveTvManager.SaveListingProvider(request).Result; + return ToOptimizedResult(result); + } + + public void Delete(DeleteListingProvider request) { var config = GetConfiguration(); - config.TunerHosts.Add(new TunerHostInfo - { - Id = Guid.NewGuid().ToString("N"), - Url = request.Url, - Type = request.Type - }); + config.ListingProviders = config.ListingProviders.Where(i => !string.Equals(request.Id, i.Id, StringComparison.OrdinalIgnoreCase)).ToList(); _config.SaveConfiguration("livetv", config); } + public void Post(AddTunerHost request) + { + var task = _liveTvManager.SaveTunerHost(request); + Task.WaitAll(task); + } + public void Delete(DeleteTunerHost request) { var config = GetConfiguration(); @@ -401,6 +434,13 @@ namespace MediaBrowser.Api.LiveTv return _config.GetConfiguration<LiveTvOptions>("livetv"); } + public async Task<object> Get(GetLineups request) + { + var info = await _liveTvManager.GetLineups(request.Id, request.Location).ConfigureAwait(false); + + return ToOptimizedSerializedResultUsingCache(info); + } + public async Task<object> Get(GetLiveTvInfo request) { var info = await _liveTvManager.GetLiveTvInfo(CancellationToken.None).ConfigureAwait(false); diff --git a/MediaBrowser.Controller/LiveTv/IListingsProvider.cs b/MediaBrowser.Controller/LiveTv/IListingsProvider.cs index beaa4eeafa..e509728bfa 100644 --- a/MediaBrowser.Controller/LiveTv/IListingsProvider.cs +++ b/MediaBrowser.Controller/LiveTv/IListingsProvider.cs @@ -1,4 +1,5 @@ -using MediaBrowser.Model.LiveTv; +using MediaBrowser.Model.Dto; +using MediaBrowser.Model.LiveTv; using System; using System.Collections.Generic; using System.Threading; @@ -9,7 +10,10 @@ namespace MediaBrowser.Controller.LiveTv public interface IListingsProvider { string Name { get; } + string Type { get; } Task<IEnumerable<ProgramInfo>> GetProgramsAsync(ListingsProviderInfo info, ChannelInfo channel, DateTime startDateUtc, DateTime endDateUtc, CancellationToken cancellationToken); Task AddMetadata(ListingsProviderInfo info, List<ChannelInfo> channels, CancellationToken cancellationToken); + Task Validate(ListingsProviderInfo info); + Task<List<NameIdPair>> GetLineups(ListingsProviderInfo info, string location); } } diff --git a/MediaBrowser.Controller/LiveTv/ILiveTvManager.cs b/MediaBrowser.Controller/LiveTv/ILiveTvManager.cs index 3aa1f66efb..3dbf9a9e90 100644 --- a/MediaBrowser.Controller/LiveTv/ILiveTvManager.cs +++ b/MediaBrowser.Controller/LiveTv/ILiveTvManager.cs @@ -56,12 +56,14 @@ namespace MediaBrowser.Controller.LiveTv /// <param name="id">The identifier.</param> /// <returns>Task.</returns> Task CancelSeriesTimer(string id); - + /// <summary> /// Adds the parts. /// </summary> /// <param name="services">The services.</param> - void AddParts(IEnumerable<ILiveTvService> services); + /// <param name="tunerHosts">The tuner hosts.</param> + /// <param name="listingProviders">The listing providers.</param> + void AddParts(IEnumerable<ILiveTvService> services, IEnumerable<ITunerHost> tunerHosts, IEnumerable<IListingsProvider> listingProviders); /// <summary> /// Gets the channels. @@ -337,5 +339,24 @@ namespace MediaBrowser.Controller.LiveTv /// <param name="dto">The dto.</param> /// <param name="user">The user.</param> void AddInfoToProgramDto(BaseItem item, BaseItemDto dto, User user = null); + /// <summary> + /// Saves the tuner host. + /// </summary> + /// <param name="info">The information.</param> + /// <returns>Task.</returns> + Task SaveTunerHost(TunerHostInfo info); + /// <summary> + /// Saves the listing provider. + /// </summary> + /// <param name="info">The information.</param> + /// <returns>Task.</returns> + Task<ListingsProviderInfo> SaveListingProvider(ListingsProviderInfo info); + /// <summary> + /// Gets the lineups. + /// </summary> + /// <param name="providerId">The provider identifier.</param> + /// <param name="location">The location.</param> + /// <returns>Task<List<NameIdPair>>.</returns> + Task<List<NameIdPair>> GetLineups(string providerId, string location); } } diff --git a/MediaBrowser.Controller/LiveTv/ITunerHost.cs b/MediaBrowser.Controller/LiveTv/ITunerHost.cs index 2fa538c605..38ed43bd97 100644 --- a/MediaBrowser.Controller/LiveTv/ITunerHost.cs +++ b/MediaBrowser.Controller/LiveTv/ITunerHost.cs @@ -46,5 +46,11 @@ namespace MediaBrowser.Controller.LiveTv /// <param name="cancellationToken">The cancellation token.</param> /// <returns>Task<MediaSourceInfo>.</returns> Task<MediaSourceInfo> GetChannelStream(TunerHostInfo info, string channelId, string streamId, CancellationToken cancellationToken); + /// <summary> + /// Validates the specified information. + /// </summary> + /// <param name="info">The information.</param> + /// <returns>Task.</returns> + Task Validate(TunerHostInfo info); } } diff --git a/MediaBrowser.Model/LiveTv/LiveTvOptions.cs b/MediaBrowser.Model/LiveTv/LiveTvOptions.cs index c78fbe630a..90cd8924d2 100644 --- a/MediaBrowser.Model/LiveTv/LiveTvOptions.cs +++ b/MediaBrowser.Model/LiveTv/LiveTvOptions.cs @@ -28,10 +28,11 @@ namespace MediaBrowser.Model.LiveTv public class ListingsProviderInfo { - public string ProviderName { get; set; } + public string Id { get; set; } + public string Type { get; set; } public string Username { get; set; } public string Password { get; set; } - public string ZipCode { get; set; } public string ListingsId { get; set; } + public string ZipCode { get; set; } } } \ No newline at end of file diff --git a/MediaBrowser.Server.Implementations/LiveTv/EmbyTV/EmbyTV.cs b/MediaBrowser.Server.Implementations/LiveTv/EmbyTV/EmbyTV.cs index 26e0709215..6e8213ee09 100644 --- a/MediaBrowser.Server.Implementations/LiveTv/EmbyTV/EmbyTV.cs +++ b/MediaBrowser.Server.Implementations/LiveTv/EmbyTV/EmbyTV.cs @@ -30,18 +30,16 @@ namespace MediaBrowser.Server.Implementations.LiveTv.EmbyTV private readonly ItemDataProvider<SeriesTimerInfo> _seriesTimerProvider; private readonly TimerManager _timerProvider; - private readonly List<ITunerHost> _tunerHosts = new List<ITunerHost>(); - private readonly List<IListingsProvider> _listingProviders = new List<IListingsProvider>(); + private readonly LiveTvManager _liveTvManager; - public EmbyTV(IApplicationHost appHost, ILogger logger, IJsonSerializer jsonSerializer, IHttpClient httpClient, IConfigurationManager config) + public EmbyTV(IApplicationHost appHost, ILogger logger, IJsonSerializer jsonSerializer, IHttpClient httpClient, IConfigurationManager config, ILiveTvManager liveTvManager) { _appHpst = appHost; _logger = logger; _httpClient = httpClient; _config = config; + _liveTvManager = (LiveTvManager)liveTvManager; _jsonSerializer = jsonSerializer; - _tunerHosts.AddRange(appHost.GetExports<ITunerHost>()); - _listingProviders.AddRange(appHost.GetExports<IListingsProvider>()); _recordingProvider = new ItemDataProvider<RecordingInfo>(jsonSerializer, _logger, Path.Combine(DataPath, "recordings"), (r1, r2) => string.Equals(r1.Id, r2.Id, StringComparison.OrdinalIgnoreCase)); _seriesTimerProvider = new SeriesTimerManager(jsonSerializer, _logger, Path.Combine(DataPath, "seriestimers")); @@ -76,7 +74,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv.EmbyTV var status = new LiveTvServiceStatusInfo(); var list = new List<LiveTvTunerInfo>(); - foreach (var host in _tunerHosts) + foreach (var host in _liveTvManager.TunerHosts) { foreach (var hostInstance in host.GetTunerHosts()) { @@ -104,7 +102,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv.EmbyTV { var list = new List<ChannelInfo>(); - foreach (var host in _tunerHosts) + foreach (var host in _liveTvManager.TunerHosts) { foreach (var hostInstance in host.GetTunerHosts()) { @@ -288,7 +286,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv.EmbyTV return GetConfiguration().ListingProviders .Select(i => { - var provider = _listingProviders.FirstOrDefault(l => string.Equals(l.Name, i.ProviderName, StringComparison.OrdinalIgnoreCase)); + var provider = _liveTvManager.ListingProviders.FirstOrDefault(l => string.Equals(l.Type, i.Type, StringComparison.OrdinalIgnoreCase)); return provider == null ? null : new Tuple<IListingsProvider, ListingsProviderInfo>(provider, i); }) diff --git a/MediaBrowser.Server.Implementations/LiveTv/Listings/SchedulesDirect.cs b/MediaBrowser.Server.Implementations/LiveTv/Listings/SchedulesDirect.cs index 3b7564983e..f5b41f3df7 100644 --- a/MediaBrowser.Server.Implementations/LiveTv/Listings/SchedulesDirect.cs +++ b/MediaBrowser.Server.Implementations/LiveTv/Listings/SchedulesDirect.cs @@ -422,7 +422,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv.Listings return images; } - public async Task<List<NameIdPair>> GetHeadends(ListingsProviderInfo info, CancellationToken cancellationToken) + public async Task<List<NameIdPair>> GetHeadends(ListingsProviderInfo info, string location, CancellationToken cancellationToken) { var token = await GetToken(info, cancellationToken); @@ -437,7 +437,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv.Listings var options = new HttpRequestOptions() { - Url = ApiUrl + "/headends?country=USA&postalcode=" + info.ZipCode, + Url = ApiUrl + "/headends?country=USA&postalcode=" + location, UserAgent = UserAgent, CancellationToken = cancellationToken }; @@ -484,43 +484,43 @@ namespace MediaBrowser.Server.Implementations.LiveTv.Listings private async Task<string> GetToken(ListingsProviderInfo info, CancellationToken cancellationToken) { - await _tokenSemaphore.WaitAsync(cancellationToken).ConfigureAwait(false); - try - { - var username = info.Username; + var username = info.Username; - // Reset the token if there's no username - if (string.IsNullOrWhiteSpace(username)) - { - return null; - } + // Reset the token if there's no username + if (string.IsNullOrWhiteSpace(username)) + { + return null; + } - var password = info.Password; - if (string.IsNullOrWhiteSpace(password)) - { - return null; - } + var password = info.Password; + if (string.IsNullOrWhiteSpace(password)) + { + return null; + } - NameValuePair savedToken = null; - if (!_tokens.TryGetValue(username, out savedToken)) - { - savedToken = new NameValuePair(); - _tokens.TryAdd(username, savedToken); - } + NameValuePair savedToken = null; + if (!_tokens.TryGetValue(username, out savedToken)) + { + savedToken = new NameValuePair(); + _tokens.TryAdd(username, savedToken); + } - if (!string.IsNullOrWhiteSpace(savedToken.Name) && !string.IsNullOrWhiteSpace(savedToken.Value)) + if (!string.IsNullOrWhiteSpace(savedToken.Name) && !string.IsNullOrWhiteSpace(savedToken.Value)) + { + long ticks; + if (long.TryParse(savedToken.Value, NumberStyles.Any, CultureInfo.InvariantCulture, out ticks)) { - long ticks; - if (long.TryParse(savedToken.Value, NumberStyles.Any, CultureInfo.InvariantCulture, out ticks)) + // If it's under 24 hours old we can still use it + if ((DateTime.UtcNow.Ticks - ticks) < TimeSpan.FromHours(24).Ticks) { - // If it's under 24 hours old we can still use it - if ((DateTime.UtcNow.Ticks - ticks) < TimeSpan.FromHours(24).Ticks) - { - return savedToken.Name; - } + return savedToken.Name; } } + } + await _tokenSemaphore.WaitAsync(cancellationToken).ConfigureAwait(false); + try + { var result = await GetTokenInternal(username, password, cancellationToken).ConfigureAwait(false); savedToken.Name = result; savedToken.Value = DateTime.UtcNow.Ticks.ToString(CultureInfo.InvariantCulture); @@ -563,6 +563,11 @@ namespace MediaBrowser.Server.Implementations.LiveTv.Listings get { return "Schedules Direct"; } } + public string Type + { + get { return "SchedulesDirect"; } + } + public class ScheduleDirect { public class Token @@ -842,5 +847,13 @@ namespace MediaBrowser.Server.Implementations.LiveTv.Listings } + public async Task Validate(ListingsProviderInfo info) + { + } + + public Task<List<NameIdPair>> GetLineups(ListingsProviderInfo info, string location) + { + return GetHeadends(info, location, CancellationToken.None); + } } } diff --git a/MediaBrowser.Server.Implementations/LiveTv/LiveTvManager.cs b/MediaBrowser.Server.Implementations/LiveTv/LiveTvManager.cs index 05bc276b86..a64ce31cf8 100644 --- a/MediaBrowser.Server.Implementations/LiveTv/LiveTvManager.cs +++ b/MediaBrowser.Server.Implementations/LiveTv/LiveTvManager.cs @@ -57,6 +57,9 @@ namespace MediaBrowser.Server.Implementations.LiveTv private readonly ConcurrentDictionary<Guid, Guid> _refreshedPrograms = new ConcurrentDictionary<Guid, Guid>(); + private readonly List<ITunerHost> _tunerHosts = new List<ITunerHost>(); + private readonly List<IListingsProvider> _listingProviders = new List<IListingsProvider>(); + public LiveTvManager(IApplicationHost appHost, IServerConfigurationManager config, ILogger logger, IItemRepository itemRepo, IImageProcessor imageProcessor, IUserDataManager userDataManager, IDtoService dtoService, IUserManager userManager, ILibraryManager libraryManager, ITaskManager taskManager, ILocalizationManager localization, IJsonSerializer jsonSerializer, IProviderManager providerManager) { _config = config; @@ -92,9 +95,13 @@ namespace MediaBrowser.Server.Implementations.LiveTv /// Adds the parts. /// </summary> /// <param name="services">The services.</param> - public void AddParts(IEnumerable<ILiveTvService> services) + /// <param name="tunerHosts">The tuner hosts.</param> + /// <param name="listingProviders">The listing providers.</param> + public void AddParts(IEnumerable<ILiveTvService> services, IEnumerable<ITunerHost> tunerHosts, IEnumerable<IListingsProvider> listingProviders) { _services.AddRange(services); + _tunerHosts.AddRange(tunerHosts); + _listingProviders.AddRange(listingProviders); foreach (var service in _services) { @@ -102,6 +109,16 @@ namespace MediaBrowser.Server.Implementations.LiveTv } } + public List<ITunerHost> TunerHosts + { + get { return _tunerHosts; } + } + + public List<IListingsProvider> ListingProviders + { + get { return _listingProviders; } + } + void service_DataSourceChanged(object sender, EventArgs e) { _taskManager.CancelIfRunningAndQueue<RefreshChannelsScheduledTask>(); @@ -2154,5 +2171,84 @@ namespace MediaBrowser.Server.Implementations.LiveTv var user = _userManager.GetUserById(userId); return await _libraryManager.GetNamedView(user, name, "livetv", "zz_" + name, cancellationToken).ConfigureAwait(false); } + + public async Task SaveTunerHost(TunerHostInfo info) + { + info = (TunerHostInfo)_jsonSerializer.DeserializeFromString(_jsonSerializer.SerializeToString(info), typeof(TunerHostInfo)); + + var provider = _tunerHosts.FirstOrDefault(i => string.Equals(info.Type, i.Type, StringComparison.OrdinalIgnoreCase)); + + if (provider == null) + { + throw new ResourceNotFoundException(); + } + + await provider.Validate(info).ConfigureAwait(false); + + var config = GetConfiguration(); + + var index = config.TunerHosts.FindIndex(i => string.Equals(i.Id, info.Id, StringComparison.OrdinalIgnoreCase)); + + if (index == -1 || string.IsNullOrWhiteSpace(info.Id)) + { + info.Id = Guid.NewGuid().ToString("N"); + config.TunerHosts.Add(info); + } + else + { + config.TunerHosts[index] = info; + } + + _config.SaveConfiguration("livetv", config); + } + + public async Task<ListingsProviderInfo> SaveListingProvider(ListingsProviderInfo info) + { + info = (ListingsProviderInfo)_jsonSerializer.DeserializeFromString(_jsonSerializer.SerializeToString(info), typeof(ListingsProviderInfo)); + + var provider = _listingProviders.FirstOrDefault(i => string.Equals(info.Type, i.Type, StringComparison.OrdinalIgnoreCase)); + + if (provider == null) + { + throw new ResourceNotFoundException(); + } + + await provider.Validate(info).ConfigureAwait(false); + + var config = GetConfiguration(); + + var index = config.ListingProviders.FindIndex(i => string.Equals(i.Id, info.Id, StringComparison.OrdinalIgnoreCase)); + + if (index == -1 || string.IsNullOrWhiteSpace(info.Id)) + { + info.Id = Guid.NewGuid().ToString("N"); + config.ListingProviders.Add(info); + } + else + { + config.ListingProviders[index] = info; + } + + _config.SaveConfiguration("livetv", config); + + return info; + } + + + public Task<List<NameIdPair>> GetLineups(string providerId, string location) + { + var config = GetConfiguration(); + + var info = config.ListingProviders.FirstOrDefault(i => string.Equals(i.Id, providerId, StringComparison.OrdinalIgnoreCase)); + + var provider = _listingProviders.FirstOrDefault(i => string.Equals(info.Type, i.Type, StringComparison.OrdinalIgnoreCase)); + + if (provider == null) + { + throw new ResourceNotFoundException(); + } + + return provider.GetLineups(info, location); + } } } diff --git a/MediaBrowser.Server.Implementations/LiveTv/TunerHosts/HdHomerun.cs b/MediaBrowser.Server.Implementations/LiveTv/TunerHosts/HdHomerun.cs index b5b588682a..9aacd0c1ea 100644 --- a/MediaBrowser.Server.Implementations/LiveTv/TunerHosts/HdHomerun.cs +++ b/MediaBrowser.Server.Implementations/LiveTv/TunerHosts/HdHomerun.cs @@ -3,7 +3,6 @@ using MediaBrowser.Common.Net; using MediaBrowser.Controller.LiveTv; using MediaBrowser.Model.Dto; using MediaBrowser.Model.Entities; -using MediaBrowser.Model.Extensions; using MediaBrowser.Model.LiveTv; using MediaBrowser.Model.Logging; using MediaBrowser.Model.MediaInfo; @@ -15,7 +14,6 @@ using System.IO; using System.Linq; using System.Threading; using System.Threading.Tasks; -using MediaBrowser.Server.Implementations.LiveTv.EmbyTV; namespace MediaBrowser.Server.Implementations.LiveTv.TunerHosts { @@ -222,5 +220,11 @@ namespace MediaBrowser.Server.Implementations.LiveTv.TunerHosts } throw new ApplicationException("Channel not found."); } + + + public async Task Validate(TunerHostInfo info) + { + await GetChannels(info, CancellationToken.None).ConfigureAwait(false); + } } } diff --git a/MediaBrowser.Server.Implementations/LiveTv/TunerHosts/M3UTunerHost.cs b/MediaBrowser.Server.Implementations/LiveTv/TunerHosts/M3UTunerHost.cs index 615e07a822..e91bd0f0bb 100644 --- a/MediaBrowser.Server.Implementations/LiveTv/TunerHosts/M3UTunerHost.cs +++ b/MediaBrowser.Server.Implementations/LiveTv/TunerHosts/M3UTunerHost.cs @@ -185,5 +185,13 @@ namespace MediaBrowser.Server.Implementations.LiveTv.TunerHosts { } } + + public async Task Validate(TunerHostInfo info) + { + if (!File.Exists(info.Url)) + { + throw new FileNotFoundException(); + } + } } } diff --git a/MediaBrowser.Server.Implementations/Localization/JavaScript/javascript.json b/MediaBrowser.Server.Implementations/Localization/JavaScript/javascript.json index d2b998ae8e..cea0363f49 100644 --- a/MediaBrowser.Server.Implementations/Localization/JavaScript/javascript.json +++ b/MediaBrowser.Server.Implementations/Localization/JavaScript/javascript.json @@ -820,5 +820,8 @@ "MessageConfirmDeleteTunerDevice": "Are you sure you wish to delete this device?", "MessageConfirmDeleteGuideProvider": "Are you sure you wish to delete this guide provider?", "HeaderDeleteProvider": "Delete Provider", - "HeaderAddProvider": "Add Provider" + "HeaderAddProvider": "Add Provider", + "ErrorAddingTunerDevice": "There was an error adding the tuner device. Please ensure it is accessible and try again.", + "ErrorSavingTvProvider": "There was an error saving the TV provider. Please ensure it is accessible and try again.", + "ErrorGettingTvLineups": "There was an error downloading tv lineups. Please ensure your username and password are correct and try again." } diff --git a/MediaBrowser.Server.Implementations/Localization/Server/server.json b/MediaBrowser.Server.Implementations/Localization/Server/server.json index 83c2ccf5d6..fe099dc672 100644 --- a/MediaBrowser.Server.Implementations/Localization/Server/server.json +++ b/MediaBrowser.Server.Implementations/Localization/Server/server.json @@ -1483,5 +1483,8 @@ "TabTuners": "Tuners", "HeaderGuideProviders": "Guide Providers", "AddGuideProviderHelp": "Add a source for TV Guide information", - "LabelZipCode": "Zip Code" + "LabelZipCode": "Zip Code:", + "GuideProviderListingsStep": "Step 2: Select Listings", + "GuideProviderLoginStep": "Step 1: Login", + "LabelLineup": "Lineup" } diff --git a/MediaBrowser.Server.Startup.Common/ApplicationHost.cs b/MediaBrowser.Server.Startup.Common/ApplicationHost.cs index fab6682d78..adef0a45fa 100644 --- a/MediaBrowser.Server.Startup.Common/ApplicationHost.cs +++ b/MediaBrowser.Server.Startup.Common/ApplicationHost.cs @@ -784,7 +784,7 @@ namespace MediaBrowser.Server.Startup.Common ImageProcessor.AddParts(GetExports<IImageEnhancer>()); - LiveTvManager.AddParts(GetExports<ILiveTvService>()); + LiveTvManager.AddParts(GetExports<ILiveTvService>(), GetExports<ITunerHost>(), GetExports<IListingsProvider>()); SubtitleManager.AddParts(GetExports<ISubtitleProvider>()); ChapterManager.AddParts(GetExports<IChapterProvider>()); diff --git a/MediaBrowser.WebDashboard/MediaBrowser.WebDashboard.csproj b/MediaBrowser.WebDashboard/MediaBrowser.WebDashboard.csproj index 1920a9ed79..bc2b8eb7a1 100644 --- a/MediaBrowser.WebDashboard/MediaBrowser.WebDashboard.csproj +++ b/MediaBrowser.WebDashboard/MediaBrowser.WebDashboard.csproj @@ -183,7 +183,7 @@ <Content Include="dashboard-ui\livetvguide.html"> <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory> </Content> - <Content Include="dashboard-ui\livetvguidesettings.html"> + <Content Include="dashboard-ui\livetvguideprovider-scd.html"> <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory> </Content> <Content Include="dashboard-ui\livetvrecordings.html"> @@ -207,7 +207,7 @@ <Content Include="dashboard-ui\scripts\homeupcoming.js"> <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory> </Content> - <Content Include="dashboard-ui\scripts\livetvguidesettings.js"> + <Content Include="dashboard-ui\scripts\livetvguideprovider-scd.js"> <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory> </Content> <Content Include="dashboard-ui\scripts\mypreferenceshome.js"> -- cgit v1.2.3 From ba9ed26c4a60b29f25c0cf53d215b617142c0fc3 Mon Sep 17 00:00:00 2001 From: Luke Pulverenti <luke.pulverenti@gmail.com> Date: Thu, 23 Jul 2015 19:40:54 -0400 Subject: update emby tv --- MediaBrowser.Api/Playback/BaseStreamingService.cs | 2 +- MediaBrowser.Api/Playback/StreamState.cs | 2 +- MediaBrowser.Controller/LiveTv/ITunerHost.cs | 8 ++ MediaBrowser.MediaEncoding/Encoder/BaseEncoder.cs | 2 +- MediaBrowser.MediaEncoding/Encoder/EncodingJob.cs | 2 +- MediaBrowser.Model/Dto/MediaSourceInfo.cs | 4 +- MediaBrowser.Model/LiveTv/LiveTvOptions.cs | 1 + .../Library/MediaSourceManager.cs | 2 +- .../LiveTv/EmbyTV/EmbyTV.cs | 130 +++++++++++++++++---- .../LiveTv/EmbyTV/ItemDataProvider.cs | 5 +- .../LiveTv/Listings/SchedulesDirect.cs | 51 ++++++-- .../LiveTv/LiveTvManager.cs | 4 +- .../LiveTv/LiveTvMediaSourceProvider.cs | 24 ++-- .../TunerHosts/HdHomerun/HdHomerunDiscovery.cs | 12 +- .../LiveTv/TunerHosts/HdHomerun/HdHomerunHost.cs | 62 ++++++---- .../LiveTv/TunerHosts/M3UTunerHost.cs | 10 +- .../Localization/Server/server.json | 2 +- 17 files changed, 236 insertions(+), 87 deletions(-) (limited to 'MediaBrowser.Model/LiveTv') diff --git a/MediaBrowser.Api/Playback/BaseStreamingService.cs b/MediaBrowser.Api/Playback/BaseStreamingService.cs index e7885a3f8e..8505b5d3a9 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 02b7720a4a..4df6960961 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 38ed43bd97..c9a96a9cac 100644 --- a/MediaBrowser.Controller/LiveTv/ITunerHost.cs +++ b/MediaBrowser.Controller/LiveTv/ITunerHost.cs @@ -47,6 +47,14 @@ namespace MediaBrowser.Controller.LiveTv /// <returns>Task<MediaSourceInfo>.</returns> Task<MediaSourceInfo> GetChannelStream(TunerHostInfo info, string channelId, string streamId, CancellationToken cancellationToken); /// <summary> + /// Gets the channel stream media sources. + /// </summary> + /// <param name="info">The information.</param> + /// <param name="channelId">The channel identifier.</param> + /// <param name="cancellationToken">The cancellation token.</param> + /// <returns>Task<List<MediaSourceInfo>>.</returns> + Task<List<MediaSourceInfo>> GetChannelStreamMediaSources(TunerHostInfo info, string channelId, CancellationToken cancellationToken); + /// <summary> /// Validates the specified information. /// </summary> /// <param name="info">The information.</param> diff --git a/MediaBrowser.MediaEncoding/Encoder/BaseEncoder.cs b/MediaBrowser.MediaEncoding/Encoder/BaseEncoder.cs index fbfe792720..9153045e6d 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 efce5abb0e..bb32ac95bd 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 8897edcbdc..75edc6a528 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 90cd8924d2..3fc8416455 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 9b46a8057b..765acd578f 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 37b6bf0866..c32b8da10b 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<LiveTvTunerInfo>(); - 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<ChannelInfo>(); - 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<Tuple<ITunerHost, TunerHostInfo>> 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<ITunerHost, TunerHostInfo>(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<SeriesTimerInfo>)_seriesTimerProvider.GetAll()); } + private string GetOriginalChannelId(string channelId) + { + var parts = channelId.Split('-'); + + return string.Join("-", parts.Skip(1).ToArray()); + } + public async Task<IEnumerable<ProgramInfo>> 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<MediaSourceInfo> GetChannelStream(string channelId, string streamId, CancellationToken cancellationToken) + public async Task<MediaSourceInfo> 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<List<MediaSourceInfo>> GetChannelStreamMediaSources(string channelId, CancellationToken cancellationToken) + public async Task<List<MediaSourceInfo>> 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<List<MediaSourceInfo>> GetRecordingStreamMediaSources(string recordingId, CancellationToken cancellationToken) diff --git a/MediaBrowser.Server.Implementations/LiveTv/EmbyTV/ItemDataProvider.cs b/MediaBrowser.Server.Implementations/LiveTv/EmbyTV/ItemDataProvider.cs index e7feeee5a7..75dec5f970 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<T> 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 ed265d416f..72a965c6ab 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<bool> 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<ScheduleDirect.Lineups>(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<List<NameIdPair>> 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<List<NameIdPair>> 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 5be90e6ccc..6ef5651296 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 5ebb796295..cf34b6b99f 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<IEnumerable<MediaSourceInfo>> 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<string>(); - 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<string>(); + 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 4777003d63..cc2bb2d521 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 187569ab49..d9f1541c8c 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<MediaSourceInfo> 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<MediaStream> + Path = GetApiUrl(info, true) + "/auto/v" + channelId, + Protocol = MediaProtocol.Http, + MediaStreams = new List<MediaStream> { 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<List<MediaSourceInfo>> GetChannelStreamMediaSources(TunerHostInfo info, string channelId, CancellationToken cancellationToken) + { + var list = new List<MediaSourceInfo>(); + + list.Add(GetMediaSource(info, channelId, null)); + + return Task.FromResult(list); + } + + public async Task<MediaSourceInfo> 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 e91bd0f0bb..91f25bbeea 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<List<MediaSourceInfo>> 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 24df7c9837..194d406f3c 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." } -- cgit v1.2.3 From b19451284351d5b753067522e9ef82b873c08770 Mon Sep 17 00:00:00 2001 From: Luke Pulverenti <luke.pulverenti@gmail.com> Date: Sat, 25 Jul 2015 14:11:46 -0400 Subject: update tuners --- MediaBrowser.Api/LiveTv/LiveTvService.cs | 8 ++++---- MediaBrowser.Controller/LiveTv/ILiveTvManager.cs | 2 +- MediaBrowser.Model/LiveTv/LiveTvOptions.cs | 1 + MediaBrowser.Server.Implementations/LiveTv/LiveTvManager.cs | 4 +++- .../LiveTv/TunerHosts/HdHomerun/HdHomerunDiscovery.cs | 2 +- .../LiveTv/TunerHosts/HdHomerun/HdHomerunHost.cs | 9 ++++++++- .../Localization/Server/server.json | 6 ++++-- MediaBrowser.WebDashboard/MediaBrowser.WebDashboard.csproj | 12 ++++++++++++ 8 files changed, 34 insertions(+), 10 deletions(-) (limited to 'MediaBrowser.Model/LiveTv') diff --git a/MediaBrowser.Api/LiveTv/LiveTvService.cs b/MediaBrowser.Api/LiveTv/LiveTvService.cs index 6c61ef66ff..b0359194c7 100644 --- a/MediaBrowser.Api/LiveTv/LiveTvService.cs +++ b/MediaBrowser.Api/LiveTv/LiveTvService.cs @@ -334,7 +334,7 @@ namespace MediaBrowser.Api.LiveTv [Route("/LiveTv/TunerHosts", "POST", Summary = "Adds a tuner host")] [Authenticated] - public class AddTunerHost : TunerHostInfo, IReturnVoid + public class AddTunerHost : TunerHostInfo, IReturn<TunerHostInfo> { } @@ -419,10 +419,10 @@ namespace MediaBrowser.Api.LiveTv _config.SaveConfiguration("livetv", config); } - public void Post(AddTunerHost request) + public async Task<object> Post(AddTunerHost request) { - var task = _liveTvManager.SaveTunerHost(request); - Task.WaitAll(task); + var result = await _liveTvManager.SaveTunerHost(request).ConfigureAwait(false); + return ToOptimizedResult(result); } public void Delete(DeleteTunerHost request) diff --git a/MediaBrowser.Controller/LiveTv/ILiveTvManager.cs b/MediaBrowser.Controller/LiveTv/ILiveTvManager.cs index 259f6925b2..53ad6dbdc7 100644 --- a/MediaBrowser.Controller/LiveTv/ILiveTvManager.cs +++ b/MediaBrowser.Controller/LiveTv/ILiveTvManager.cs @@ -344,7 +344,7 @@ namespace MediaBrowser.Controller.LiveTv /// </summary> /// <param name="info">The information.</param> /// <returns>Task.</returns> - Task SaveTunerHost(TunerHostInfo info); + Task<TunerHostInfo> SaveTunerHost(TunerHostInfo info); /// <summary> /// Saves the listing provider. /// </summary> diff --git a/MediaBrowser.Model/LiveTv/LiveTvOptions.cs b/MediaBrowser.Model/LiveTv/LiveTvOptions.cs index 3fc8416455..004ee2ce6a 100644 --- a/MediaBrowser.Model/LiveTv/LiveTvOptions.cs +++ b/MediaBrowser.Model/LiveTv/LiveTvOptions.cs @@ -24,6 +24,7 @@ namespace MediaBrowser.Model.LiveTv public string Id { get; set; } public string Url { get; set; } public string Type { get; set; } + public bool ImportFavoritesOnly { get; set; } } public class ListingsProviderInfo diff --git a/MediaBrowser.Server.Implementations/LiveTv/LiveTvManager.cs b/MediaBrowser.Server.Implementations/LiveTv/LiveTvManager.cs index d539562b8f..b7091ee097 100644 --- a/MediaBrowser.Server.Implementations/LiveTv/LiveTvManager.cs +++ b/MediaBrowser.Server.Implementations/LiveTv/LiveTvManager.cs @@ -2172,7 +2172,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv return await _libraryManager.GetNamedView(user, name, "livetv", "zz_" + name, cancellationToken).ConfigureAwait(false); } - public async Task SaveTunerHost(TunerHostInfo info) + public async Task<TunerHostInfo> SaveTunerHost(TunerHostInfo info) { info = (TunerHostInfo)_jsonSerializer.DeserializeFromString(_jsonSerializer.SerializeToString(info), typeof(TunerHostInfo)); @@ -2202,6 +2202,8 @@ namespace MediaBrowser.Server.Implementations.LiveTv _config.SaveConfiguration("livetv", config); _taskManager.CancelIfRunningAndQueue<RefreshChannelsScheduledTask>(); + + return info; } public async Task<ListingsProviderInfo> SaveListingProvider(ListingsProviderInfo info, bool validateLogin, bool validateListings) diff --git a/MediaBrowser.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunDiscovery.cs b/MediaBrowser.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunDiscovery.cs index cc2bb2d521..10baffea61 100644 --- a/MediaBrowser.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunDiscovery.cs +++ b/MediaBrowser.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunDiscovery.cs @@ -73,7 +73,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv.TunerHosts.HdHomerun } // Strip off the port - url = new Uri(url).GetComponents(UriComponents.AbsoluteUri & ~UriComponents.Port, UriFormat.UriEscaped); + url = new Uri(url).GetComponents(UriComponents.AbsoluteUri & ~UriComponents.Port, UriFormat.UriEscaped).TrimEnd('/'); await _liveTvManager.SaveTunerHost(new TunerHostInfo { diff --git a/MediaBrowser.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunHost.cs b/MediaBrowser.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunHost.cs index 1e30a4fd8d..682abd20f4 100644 --- a/MediaBrowser.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunHost.cs +++ b/MediaBrowser.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunHost.cs @@ -60,7 +60,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv.TunerHosts.HdHomerun if (root != null) { - return root.Select(i => new ChannelInfo + var result = root.Select(i => new ChannelInfo { Name = i.GuideName, Number = i.GuideNumber.ToString(CultureInfo.InvariantCulture), @@ -68,6 +68,13 @@ namespace MediaBrowser.Server.Implementations.LiveTv.TunerHosts.HdHomerun IsFavorite = i.Favorite }); + + if (info.ImportFavoritesOnly) + { + result = result.Where(i => (i.IsFavorite ?? true)).ToList(); + } + + return result; } return new List<ChannelInfo>(); } diff --git a/MediaBrowser.Server.Implementations/Localization/Server/server.json b/MediaBrowser.Server.Implementations/Localization/Server/server.json index 2c2fd76a73..e5a36b12ff 100644 --- a/MediaBrowser.Server.Implementations/Localization/Server/server.json +++ b/MediaBrowser.Server.Implementations/Localization/Server/server.json @@ -1480,7 +1480,7 @@ "ButtonAddDevice": "Add Device", "HeaderAddDevice": "Add Device", "HeaderExternalServices": "External Services", - "LabelIpAddressPath": "IP Address / Path:", + "LabelTunerIpAddress": "Tuner IP Address:", "TabExternalServices": "External Services", "TabTuners": "Tuners", "HeaderGuideProviders": "Guide Providers", @@ -1489,5 +1489,7 @@ "GuideProviderListingsStep": "Step 2: Select Listings", "GuideProviderLoginStep": "Step 1: Login", "LabelLineup": "Lineup:", - "MessageTunerDeviceNotListed": "Is your tuner device not listed? Try installing an external service provider for more Live TV options." + "MessageTunerDeviceNotListed": "Is your tuner device not listed? Try installing an external service provider for more Live TV options.", + "LabelImportOnlyFavoriteChannels": "Restrict to channels marked as favorite", + "ImportFavoriteChannelsHelp": "If enabled, only channels that are marked as favorite on the tuner device will be imported." } diff --git a/MediaBrowser.WebDashboard/MediaBrowser.WebDashboard.csproj b/MediaBrowser.WebDashboard/MediaBrowser.WebDashboard.csproj index bc2b8eb7a1..982d68461e 100644 --- a/MediaBrowser.WebDashboard/MediaBrowser.WebDashboard.csproj +++ b/MediaBrowser.WebDashboard/MediaBrowser.WebDashboard.csproj @@ -195,6 +195,12 @@ <Content Include="dashboard-ui\livetvtimers.html"> <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory> </Content> + <Content Include="dashboard-ui\livetvtunerprovider-hdhomerun.html"> + <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory> + </Content> + <Content Include="dashboard-ui\livetvtunerprovider-m3u.html"> + <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory> + </Content> <Content Include="dashboard-ui\mypreferenceshome.html"> <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory> </Content> @@ -210,6 +216,12 @@ <Content Include="dashboard-ui\scripts\livetvguideprovider-scd.js"> <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory> </Content> + <Content Include="dashboard-ui\scripts\livetvtunerprovider-hdhomerun.js"> + <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory> + </Content> + <Content Include="dashboard-ui\scripts\livetvtunerprovider-m3u.js"> + <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory> + </Content> <Content Include="dashboard-ui\scripts\mypreferenceshome.js"> <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory> </Content> -- cgit v1.2.3 From 7f9a2f1af6c43ccf49b417884583c999e53298cd Mon Sep 17 00:00:00 2001 From: Luke Pulverenti <luke.pulverenti@gmail.com> Date: Mon, 27 Jul 2015 12:21:18 -0400 Subject: add path help messages --- MediaBrowser.Controller/LiveTv/ITunerHost.cs | 5 ----- MediaBrowser.Model/LiveTv/LiveTvOptions.cs | 6 ++++++ MediaBrowser.Model/System/SystemInfo.cs | 5 +++++ MediaBrowser.Server.Implementations/LiveTv/EmbyTV/EmbyTV.cs | 1 + MediaBrowser.Server.Implementations/LiveTv/LiveTvManager.cs | 6 +++--- .../LiveTv/RefreshChannelsScheduledTask.cs | 3 ++- .../LiveTv/TunerHosts/HdHomerun/HdHomerunHost.cs | 5 ----- .../LiveTv/TunerHosts/M3UTunerHost.cs | 5 ----- .../Localization/JavaScript/javascript.json | 7 ++++--- MediaBrowser.Server.Startup.Common/ApplicationHost.cs | 3 ++- 10 files changed, 23 insertions(+), 23 deletions(-) (limited to 'MediaBrowser.Model/LiveTv') diff --git a/MediaBrowser.Controller/LiveTv/ITunerHost.cs b/MediaBrowser.Controller/LiveTv/ITunerHost.cs index c9a96a9cac..a6c8021d92 100644 --- a/MediaBrowser.Controller/LiveTv/ITunerHost.cs +++ b/MediaBrowser.Controller/LiveTv/ITunerHost.cs @@ -19,11 +19,6 @@ namespace MediaBrowser.Controller.LiveTv /// <value>The type.</value> string Type { get; } /// <summary> - /// Gets the tuner hosts. - /// </summary> - /// <returns>List<TunerHostInfo>.</returns> - List<TunerHostInfo> GetTunerHosts(); - /// <summary> /// Gets the channels. /// </summary> /// <param name="info">The information.</param> diff --git a/MediaBrowser.Model/LiveTv/LiveTvOptions.cs b/MediaBrowser.Model/LiveTv/LiveTvOptions.cs index 004ee2ce6a..c5e8f46366 100644 --- a/MediaBrowser.Model/LiveTv/LiveTvOptions.cs +++ b/MediaBrowser.Model/LiveTv/LiveTvOptions.cs @@ -25,6 +25,12 @@ namespace MediaBrowser.Model.LiveTv public string Url { get; set; } public string Type { get; set; } public bool ImportFavoritesOnly { get; set; } + public bool IsEnabled { get; set; } + + public TunerHostInfo() + { + IsEnabled = true; + } } public class ListingsProviderInfo diff --git a/MediaBrowser.Model/System/SystemInfo.cs b/MediaBrowser.Model/System/SystemInfo.cs index 8c1fc759f2..094c4fda62 100644 --- a/MediaBrowser.Model/System/SystemInfo.cs +++ b/MediaBrowser.Model/System/SystemInfo.cs @@ -13,6 +13,11 @@ namespace MediaBrowser.Model.System /// </summary> /// <value>The operating sytem.</value> public string OperatingSystem { get; set; } + /// <summary> + /// Gets or sets the display name of the operating system. + /// </summary> + /// <value>The display name of the operating system.</value> + public string OperatingSystemDisplayName { get; set; } /// <summary> /// Gets or sets a value indicating whether this instance is running as service. diff --git a/MediaBrowser.Server.Implementations/LiveTv/EmbyTV/EmbyTV.cs b/MediaBrowser.Server.Implementations/LiveTv/EmbyTV/EmbyTV.cs index c32b8da10b..d5bfc5449a 100644 --- a/MediaBrowser.Server.Implementations/LiveTv/EmbyTV/EmbyTV.cs +++ b/MediaBrowser.Server.Implementations/LiveTv/EmbyTV/EmbyTV.cs @@ -134,6 +134,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv.EmbyTV private List<Tuple<ITunerHost, TunerHostInfo>> GetTunerHosts() { return GetConfiguration().TunerHosts + .Where(i => i.IsEnabled) .Select(i => { var provider = _liveTvManager.TunerHosts.FirstOrDefault(l => string.Equals(l.Type, i.Type, StringComparison.OrdinalIgnoreCase)); diff --git a/MediaBrowser.Server.Implementations/LiveTv/LiveTvManager.cs b/MediaBrowser.Server.Implementations/LiveTv/LiveTvManager.cs index b7091ee097..d8e60be5a1 100644 --- a/MediaBrowser.Server.Implementations/LiveTv/LiveTvManager.cs +++ b/MediaBrowser.Server.Implementations/LiveTv/LiveTvManager.cs @@ -2127,7 +2127,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv private bool IsLiveTvEnabled(User user) { - return user.Policy.EnableLiveTvAccess && Services.Count > 0; + return user.Policy.EnableLiveTvAccess && (Services.Count > 1 || GetConfiguration().TunerHosts.Count(i => i.IsEnabled) > 0); } public IEnumerable<User> GetEnabledUsers() @@ -2175,7 +2175,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv public async Task<TunerHostInfo> SaveTunerHost(TunerHostInfo info) { info = (TunerHostInfo)_jsonSerializer.DeserializeFromString(_jsonSerializer.SerializeToString(info), typeof(TunerHostInfo)); - + var provider = _tunerHosts.FirstOrDefault(i => string.Equals(info.Type, i.Type, StringComparison.OrdinalIgnoreCase)); if (provider == null) @@ -2236,7 +2236,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv _config.SaveConfiguration("livetv", config); _taskManager.CancelIfRunningAndQueue<RefreshChannelsScheduledTask>(); - + return info; } diff --git a/MediaBrowser.Server.Implementations/LiveTv/RefreshChannelsScheduledTask.cs b/MediaBrowser.Server.Implementations/LiveTv/RefreshChannelsScheduledTask.cs index 7cb616d3fc..fa1a8b3e72 100644 --- a/MediaBrowser.Server.Implementations/LiveTv/RefreshChannelsScheduledTask.cs +++ b/MediaBrowser.Server.Implementations/LiveTv/RefreshChannelsScheduledTask.cs @@ -5,6 +5,7 @@ using MediaBrowser.Model.LiveTv; using MediaBrowser.Model.Tasks; using System; using System.Collections.Generic; +using System.Linq; using System.Threading.Tasks; namespace MediaBrowser.Server.Implementations.LiveTv @@ -61,7 +62,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv public bool IsHidden { - get { return _liveTvManager.Services.Count == 1 && GetConfiguration().TunerHosts.Count == 0; } + get { return _liveTvManager.Services.Count == 1 && GetConfiguration().TunerHosts.Count(i => i.IsEnabled) == 0; } } public bool IsEnabled diff --git a/MediaBrowser.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunHost.cs b/MediaBrowser.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunHost.cs index 55d3e6a331..c01eb63abb 100644 --- a/MediaBrowser.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunHost.cs +++ b/MediaBrowser.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunHost.cs @@ -207,11 +207,6 @@ namespace MediaBrowser.Server.Implementations.LiveTv.TunerHosts.HdHomerun return _config.GetConfiguration<LiveTvOptions>("livetv"); } - public List<TunerHostInfo> GetTunerHosts() - { - return GetConfiguration().TunerHosts.Where(i => string.Equals(i.Type, Type, StringComparison.OrdinalIgnoreCase)).ToList(); - } - private MediaSourceInfo GetMediaSource(TunerHostInfo info, string channelId, string profile) { int? width = null; diff --git a/MediaBrowser.Server.Implementations/LiveTv/TunerHosts/M3UTunerHost.cs b/MediaBrowser.Server.Implementations/LiveTv/TunerHosts/M3UTunerHost.cs index 91f25bbeea..bb31390f23 100644 --- a/MediaBrowser.Server.Implementations/LiveTv/TunerHosts/M3UTunerHost.cs +++ b/MediaBrowser.Server.Implementations/LiveTv/TunerHosts/M3UTunerHost.cs @@ -124,11 +124,6 @@ namespace MediaBrowser.Server.Implementations.LiveTv.TunerHosts return _config.GetConfiguration<LiveTvOptions>("livetv"); } - public List<TunerHostInfo> GetTunerHosts() - { - return GetConfiguration().TunerHosts.Where(i => string.Equals(i.Type, Type, StringComparison.OrdinalIgnoreCase)).ToList(); - } - public async Task<MediaSourceInfo> GetChannelStream(TunerHostInfo info, string channelId, string streamId, CancellationToken cancellationToken) { var channels = await GetChannels(info, cancellationToken).ConfigureAwait(false); diff --git a/MediaBrowser.Server.Implementations/Localization/JavaScript/javascript.json b/MediaBrowser.Server.Implementations/Localization/JavaScript/javascript.json index acd54cb0fa..2e61d181ba 100644 --- a/MediaBrowser.Server.Implementations/Localization/JavaScript/javascript.json +++ b/MediaBrowser.Server.Implementations/Localization/JavaScript/javascript.json @@ -288,6 +288,7 @@ "HeaderSelectPath": "Select Path", "ButtonNetwork": "Network", "MessageDirectoryPickerInstruction": "Network paths can be entered manually in the event the Network button fails to locate your devices. For example, {0} or {1}.", + "MessageDirectoryPickerBSDInstruction": "For BSD, you may need to configure storage within your FreeNAS Jail in order to allow Emby to access it.", "HeaderMenu": "Menu", "ButtonOpen": "Open", "ButtonOpenInNewTab": "Open in new tab", @@ -828,7 +829,7 @@ "ErrorPleaseSelectLineup": "Please select a lineup and try again. If no lineups are available, then please check that your username, password, and postal code is correct.", "HeaderTryCinemaMode": "Try Cinema Mode", "ButtonBecomeSupporter": "Become an Emby Supporter", - "ButtonClosePlayVideo": "Close and play my video", - "MessageDidYouKnowCinemaMode": "Did you know that by becoming an Emby Supporter, you can enhance your experience with features like Cinema Mode?", - "MessageDidYouKnowCinemaMode2": "Cinema Mode gives you the true cinema experience with trailers and custom intros before the main feature." + "ButtonClosePlayVideo": "Close and play my media", + "MessageDidYouKnowCinemaMode": "Did you know that by becoming an Emby Supporter, you can enhance your experience with features like Cinema Mode?", + "MessageDidYouKnowCinemaMode2": "Cinema Mode gives you the true cinema experience with trailers and custom intros before the main feature." } diff --git a/MediaBrowser.Server.Startup.Common/ApplicationHost.cs b/MediaBrowser.Server.Startup.Common/ApplicationHost.cs index 5e5babbb40..b554e0d1cf 100644 --- a/MediaBrowser.Server.Startup.Common/ApplicationHost.cs +++ b/MediaBrowser.Server.Startup.Common/ApplicationHost.cs @@ -1055,7 +1055,8 @@ namespace MediaBrowser.Server.Startup.Common HttpServerPortNumber = HttpPort, SupportsHttps = SupportsHttps, HttpsPortNumber = HttpsPort, - OperatingSystem = OperatingSystemDisplayName, + OperatingSystem = NativeApp.Environment.OperatingSystem.ToString(), + OperatingSystemDisplayName = OperatingSystemDisplayName, CanSelfRestart = CanSelfRestart, CanSelfUpdate = CanSelfUpdate, WanAddress = ConnectManager.WanApiAddress, -- cgit v1.2.3 From edecae6ed5bcd7159ac2ba2c12d8d38824915129 Mon Sep 17 00:00:00 2001 From: Luke Pulverenti <luke.pulverenti@gmail.com> Date: Sun, 2 Aug 2015 13:02:23 -0400 Subject: improve guide loading performance --- Emby.Drawing/ImageProcessor.cs | 26 +++---- MediaBrowser.Api/LiveTv/LiveTvService.cs | 80 +++++++++++++++++++--- MediaBrowser.Controller/LiveTv/ILiveTvManager.cs | 15 ++-- MediaBrowser.Dlna/Didl/DidlBuilder.cs | 18 ++--- MediaBrowser.Model/Channels/ChannelQuery.cs | 14 +++- MediaBrowser.Model/LiveTv/ProgramQuery.cs | 10 +++ .../LiveTv/RecommendedProgramQuery.cs | 14 +++- MediaBrowser.Model/LiveTv/RecordingQuery.cs | 14 +++- .../Dto/DtoService.cs | 5 -- .../Library/MediaSourceManager.cs | 4 ++ .../LiveTv/LiveTvDtoService.cs | 5 +- .../LiveTv/LiveTvManager.cs | 14 ++-- 12 files changed, 166 insertions(+), 53 deletions(-) (limited to 'MediaBrowser.Model/LiveTv') diff --git a/Emby.Drawing/ImageProcessor.cs b/Emby.Drawing/ImageProcessor.cs index 2ba4f5aab7..1e4537baef 100644 --- a/Emby.Drawing/ImageProcessor.cs +++ b/Emby.Drawing/ImageProcessor.cs @@ -410,18 +410,20 @@ namespace Emby.Drawing { ImageSize size; - try - { - size = ImageHeader.GetDimensions(path, _logger, _fileSystem); - } - catch - { - _logger.Info("Failed to read image header for {0}. Doing it the slow way.", path); - - CheckDisposed(); - - size = _imageEncoder.GetImageSize(path); - } + size = ImageHeader.GetDimensions(path, _logger, _fileSystem); + //try + //{ + // size = ImageHeader.GetDimensions(path, _logger, _fileSystem); + //} + //catch + //{ + // return; + // //_logger.Info("Failed to read image header for {0}. Doing it the slow way.", path); + + // //CheckDisposed(); + + // //size = _imageEncoder.GetImageSize(path); + //} StartSaveImageSizeTimer(); diff --git a/MediaBrowser.Api/LiveTv/LiveTvService.cs b/MediaBrowser.Api/LiveTv/LiveTvService.cs index 6814ad751b..3ff4c4828e 100644 --- a/MediaBrowser.Api/LiveTv/LiveTvService.cs +++ b/MediaBrowser.Api/LiveTv/LiveTvService.cs @@ -29,7 +29,7 @@ namespace MediaBrowser.Api.LiveTv [Route("/LiveTv/Channels", "GET", Summary = "Gets available live tv channels.")] [Authenticated] - public class GetChannels : IReturn<QueryResult<ChannelInfoDto>> + public class GetChannels : IReturn<QueryResult<ChannelInfoDto>>, IHasDtoOptions { [ApiMember(Name = "Type", Description = "Optional filter by channel type.", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET")] public ChannelType? Type { get; set; } @@ -62,6 +62,22 @@ namespace MediaBrowser.Api.LiveTv [ApiMember(Name = "EnableFavoriteSorting", Description = "Incorporate favorite and like status into channel sorting.", IsRequired = false, DataType = "bool", ParameterType = "query", Verb = "GET")] public bool EnableFavoriteSorting { get; set; } + + [ApiMember(Name = "EnableImages", Description = "Optional, include image information in output", IsRequired = false, DataType = "boolean", ParameterType = "query", Verb = "GET")] + public bool? EnableImages { get; set; } + + [ApiMember(Name = "ImageTypeLimit", Description = "Optional, the max number of images to return, per image type", IsRequired = false, DataType = "int", ParameterType = "query", Verb = "GET")] + public int? ImageTypeLimit { get; set; } + + [ApiMember(Name = "EnableImageTypes", Description = "Optional. The image types to include in the output.", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET")] + public string EnableImageTypes { get; set; } + + /// <summary> + /// Fields to return within the items, in addition to basic information + /// </summary> + /// <value>The fields.</value> + [ApiMember(Name = "Fields", Description = "Optional. Specify additional fields of information to return in the output. This allows multiple, comma delimeted. Options: Budget, Chapters, CriticRatingSummary, DateCreated, Genres, HomePageUrl, IndexOptions, MediaStreams, Overview, ParentId, Path, People, ProviderIds, PrimaryImageAspectRatio, Revenue, SortName, Studios, Taglines", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET", AllowMultiple = true)] + public string Fields { get; set; } } [Route("/LiveTv/Channels/{Id}", "GET", Summary = "Gets a live tv channel")] @@ -81,7 +97,7 @@ namespace MediaBrowser.Api.LiveTv [Route("/LiveTv/Recordings", "GET", Summary = "Gets live tv recordings")] [Authenticated] - public class GetRecordings : IReturn<QueryResult<BaseItemDto>> + public class GetRecordings : IReturn<QueryResult<BaseItemDto>>, IHasDtoOptions { [ApiMember(Name = "ChannelId", Description = "Optional filter by channel id.", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET")] public string ChannelId { get; set; } @@ -106,6 +122,22 @@ namespace MediaBrowser.Api.LiveTv [ApiMember(Name = "SeriesTimerId", Description = "Optional filter by recordings belonging to a series timer", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET")] public string SeriesTimerId { get; set; } + + [ApiMember(Name = "EnableImages", Description = "Optional, include image information in output", IsRequired = false, DataType = "boolean", ParameterType = "query", Verb = "GET")] + public bool? EnableImages { get; set; } + + [ApiMember(Name = "ImageTypeLimit", Description = "Optional, the max number of images to return, per image type", IsRequired = false, DataType = "int", ParameterType = "query", Verb = "GET")] + public int? ImageTypeLimit { get; set; } + + [ApiMember(Name = "EnableImageTypes", Description = "Optional. The image types to include in the output.", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET")] + public string EnableImageTypes { get; set; } + + /// <summary> + /// Fields to return within the items, in addition to basic information + /// </summary> + /// <value>The fields.</value> + [ApiMember(Name = "Fields", Description = "Optional. Specify additional fields of information to return in the output. This allows multiple, comma delimeted. Options: Budget, Chapters, CriticRatingSummary, DateCreated, Genres, HomePageUrl, IndexOptions, MediaStreams, Overview, ParentId, Path, People, ProviderIds, PrimaryImageAspectRatio, Revenue, SortName, Studios, Taglines", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET", AllowMultiple = true)] + public string Fields { get; set; } } [Route("/LiveTv/Recordings/Groups", "GET", Summary = "Gets live tv recording groups")] @@ -164,7 +196,7 @@ namespace MediaBrowser.Api.LiveTv [Route("/LiveTv/Programs", "GET,POST", Summary = "Gets available live tv epgs..")] [Authenticated] - public class GetPrograms : IReturn<QueryResult<BaseItemDto>> + public class GetPrograms : IReturn<QueryResult<BaseItemDto>>, IHasDtoOptions { [ApiMember(Name = "ChannelIds", Description = "The channels to return guide information for.", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET,POST")] public string ChannelIds { get; set; } @@ -207,11 +239,27 @@ namespace MediaBrowser.Api.LiveTv [ApiMember(Name = "Genres", Description = "The genres to return guide information for.", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET,POST")] public string Genres { get; set; } + + [ApiMember(Name = "EnableImages", Description = "Optional, include image information in output", IsRequired = false, DataType = "boolean", ParameterType = "query", Verb = "GET")] + public bool? EnableImages { get; set; } + + [ApiMember(Name = "ImageTypeLimit", Description = "Optional, the max number of images to return, per image type", IsRequired = false, DataType = "int", ParameterType = "query", Verb = "GET")] + public int? ImageTypeLimit { get; set; } + + [ApiMember(Name = "EnableImageTypes", Description = "Optional. The image types to include in the output.", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET")] + public string EnableImageTypes { get; set; } + + /// <summary> + /// Fields to return within the items, in addition to basic information + /// </summary> + /// <value>The fields.</value> + [ApiMember(Name = "Fields", Description = "Optional. Specify additional fields of information to return in the output. This allows multiple, comma delimeted. Options: Budget, Chapters, CriticRatingSummary, DateCreated, Genres, HomePageUrl, IndexOptions, MediaStreams, Overview, ParentId, Path, People, ProviderIds, PrimaryImageAspectRatio, Revenue, SortName, Studios, Taglines", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET", AllowMultiple = true)] + public string Fields { get; set; } } [Route("/LiveTv/Programs/Recommended", "GET", Summary = "Gets available live tv epgs..")] [Authenticated] - public class GetRecommendedPrograms : IReturn<QueryResult<BaseItemDto>> + public class GetRecommendedPrograms : IReturn<QueryResult<BaseItemDto>>, IHasDtoOptions { [ApiMember(Name = "UserId", Description = "Optional filter by user id.", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET,POST")] public string UserId { get; set; } @@ -230,6 +278,22 @@ namespace MediaBrowser.Api.LiveTv [ApiMember(Name = "IsMovie", Description = "Optional filter for movies.", IsRequired = false, DataType = "bool", ParameterType = "query", Verb = "GET")] public bool? IsMovie { get; set; } + + [ApiMember(Name = "EnableImages", Description = "Optional, include image information in output", IsRequired = false, DataType = "boolean", ParameterType = "query", Verb = "GET")] + public bool? EnableImages { get; set; } + + [ApiMember(Name = "ImageTypeLimit", Description = "Optional, the max number of images to return, per image type", IsRequired = false, DataType = "int", ParameterType = "query", Verb = "GET")] + public int? ImageTypeLimit { get; set; } + + [ApiMember(Name = "EnableImageTypes", Description = "Optional. The image types to include in the output.", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET")] + public string EnableImageTypes { get; set; } + + /// <summary> + /// Fields to return within the items, in addition to basic information + /// </summary> + /// <value>The fields.</value> + [ApiMember(Name = "Fields", Description = "Optional. Specify additional fields of information to return in the output. This allows multiple, comma delimeted. Options: Budget, Chapters, CriticRatingSummary, DateCreated, Genres, HomePageUrl, IndexOptions, MediaStreams, Overview, ParentId, Path, People, ProviderIds, PrimaryImageAspectRatio, Revenue, SortName, Studios, Taglines", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET", AllowMultiple = true)] + public string Fields { get; set; } } [Route("/LiveTv/Programs/{Id}", "GET", Summary = "Gets a live tv program")] @@ -490,7 +554,7 @@ namespace MediaBrowser.Api.LiveTv IsDisliked = request.IsDisliked, EnableFavoriteSorting = request.EnableFavoriteSorting - }, CancellationToken.None).ConfigureAwait(false); + }, GetDtoOptions(request), CancellationToken.None).ConfigureAwait(false); return ToOptimizedSerializedResultUsingCache(result); } @@ -546,7 +610,7 @@ namespace MediaBrowser.Api.LiveTv query.IsSports = request.IsSports; query.Genres = (request.Genres ?? String.Empty).Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries); - var result = await _liveTvManager.GetPrograms(query, CancellationToken.None).ConfigureAwait(false); + var result = await _liveTvManager.GetPrograms(query, GetDtoOptions(request), CancellationToken.None).ConfigureAwait(false); return ToOptimizedResult(result); } @@ -563,7 +627,7 @@ namespace MediaBrowser.Api.LiveTv IsSports = request.IsSports }; - var result = await _liveTvManager.GetRecommendedPrograms(query, CancellationToken.None).ConfigureAwait(false); + var result = await _liveTvManager.GetRecommendedPrograms(query, GetDtoOptions(request), CancellationToken.None).ConfigureAwait(false); return ToOptimizedResult(result); } @@ -575,7 +639,7 @@ namespace MediaBrowser.Api.LiveTv public async Task<object> Get(GetRecordings request) { - var options = new DtoOptions(); + var options = GetDtoOptions(request); options.DeviceId = AuthorizationContext.GetAuthorizationInfo(Request).DeviceId; var result = await _liveTvManager.GetRecordings(new RecordingQuery diff --git a/MediaBrowser.Controller/LiveTv/ILiveTvManager.cs b/MediaBrowser.Controller/LiveTv/ILiveTvManager.cs index 53ad6dbdc7..8898753837 100644 --- a/MediaBrowser.Controller/LiveTv/ILiveTvManager.cs +++ b/MediaBrowser.Controller/LiveTv/ILiveTvManager.cs @@ -69,9 +69,10 @@ namespace MediaBrowser.Controller.LiveTv /// Gets the channels. /// </summary> /// <param name="query">The query.</param> + /// <param name="options">The options.</param> /// <param name="cancellationToken">The cancellation token.</param> /// <returns>IEnumerable{Channel}.</returns> - Task<QueryResult<ChannelInfoDto>> GetChannels(LiveTvChannelQuery query, CancellationToken cancellationToken); + Task<QueryResult<ChannelInfoDto>> GetChannels(LiveTvChannelQuery query, DtoOptions options, CancellationToken cancellationToken); /// <summary> /// Gets the recording. @@ -173,14 +174,15 @@ namespace MediaBrowser.Controller.LiveTv /// <param name="user">The user.</param> /// <returns>Task{ProgramInfoDto}.</returns> Task<BaseItemDto> GetProgram(string id, CancellationToken cancellationToken, User user = null); - + /// <summary> /// Gets the programs. /// </summary> /// <param name="query">The query.</param> + /// <param name="options">The options.</param> /// <param name="cancellationToken">The cancellation token.</param> /// <returns>IEnumerable{ProgramInfo}.</returns> - Task<QueryResult<BaseItemDto>> GetPrograms(ProgramQuery query, CancellationToken cancellationToken); + Task<QueryResult<BaseItemDto>> GetPrograms(ProgramQuery query, DtoOptions options, CancellationToken cancellationToken); /// <summary> /// Updates the timer. @@ -240,10 +242,10 @@ namespace MediaBrowser.Controller.LiveTv /// Gets the recommended programs. /// </summary> /// <param name="query">The query.</param> + /// <param name="options">The options.</param> /// <param name="cancellationToken">The cancellation token.</param> /// <returns>Task{QueryResult{ProgramInfoDto}}.</returns> - Task<QueryResult<BaseItemDto>> GetRecommendedPrograms(RecommendedProgramQuery query, - CancellationToken cancellationToken); + Task<QueryResult<BaseItemDto>> GetRecommendedPrograms(RecommendedProgramQuery query, DtoOptions options, CancellationToken cancellationToken); /// <summary> /// Gets the recommended programs internal. @@ -251,8 +253,7 @@ namespace MediaBrowser.Controller.LiveTv /// <param name="query">The query.</param> /// <param name="cancellationToken">The cancellation token.</param> /// <returns>Task<QueryResult<LiveTvProgram>>.</returns> - Task<QueryResult<LiveTvProgram>> GetRecommendedProgramsInternal(RecommendedProgramQuery query, - CancellationToken cancellationToken); + Task<QueryResult<LiveTvProgram>> GetRecommendedProgramsInternal(RecommendedProgramQuery query, CancellationToken cancellationToken); /// <summary> /// Gets the live tv information. diff --git a/MediaBrowser.Dlna/Didl/DidlBuilder.cs b/MediaBrowser.Dlna/Didl/DidlBuilder.cs index 0e4cf73924..25514f1dca 100644 --- a/MediaBrowser.Dlna/Didl/DidlBuilder.cs +++ b/MediaBrowser.Dlna/Didl/DidlBuilder.cs @@ -971,17 +971,17 @@ namespace MediaBrowser.Dlna.Didl int? width = null; int? height = null; - try - { - var size = _imageProcessor.GetImageSize(imageInfo); + //try + //{ + // var size = _imageProcessor.GetImageSize(imageInfo); - width = Convert.ToInt32(size.Width); - height = Convert.ToInt32(size.Height); - } - catch - { + // width = Convert.ToInt32(size.Width); + // height = Convert.ToInt32(size.Height); + //} + //catch + //{ - } + //} return new ImageDownloadInfo { diff --git a/MediaBrowser.Model/Channels/ChannelQuery.cs b/MediaBrowser.Model/Channels/ChannelQuery.cs index 3c6e43fde8..b63d797f43 100644 --- a/MediaBrowser.Model/Channels/ChannelQuery.cs +++ b/MediaBrowser.Model/Channels/ChannelQuery.cs @@ -1,7 +1,19 @@ -namespace MediaBrowser.Model.Channels +using MediaBrowser.Model.Entities; +using MediaBrowser.Model.Querying; + +namespace MediaBrowser.Model.Channels { public class ChannelQuery { + /// <summary> + /// Fields to return within the items, in addition to basic information + /// </summary> + /// <value>The fields.</value> + public ItemFields[] Fields { get; set; } + public bool? EnableImages { get; set; } + public int? ImageTypeLimit { get; set; } + public ImageType[] EnableImageTypes { get; set; } + /// <summary> /// Gets or sets the user identifier. /// </summary> diff --git a/MediaBrowser.Model/LiveTv/ProgramQuery.cs b/MediaBrowser.Model/LiveTv/ProgramQuery.cs index c19ba54bd1..3f652ea6f5 100644 --- a/MediaBrowser.Model/LiveTv/ProgramQuery.cs +++ b/MediaBrowser.Model/LiveTv/ProgramQuery.cs @@ -1,5 +1,6 @@ using MediaBrowser.Model.Entities; using System; +using MediaBrowser.Model.Querying; namespace MediaBrowser.Model.LiveTv { @@ -15,6 +16,15 @@ namespace MediaBrowser.Model.LiveTv Genres = new string[] { }; } + /// <summary> + /// Fields to return within the items, in addition to basic information + /// </summary> + /// <value>The fields.</value> + public ItemFields[] Fields { get; set; } + public bool? EnableImages { get; set; } + public int? ImageTypeLimit { get; set; } + public ImageType[] EnableImageTypes { get; set; } + /// <summary> /// Gets or sets the channel ids. /// </summary> diff --git a/MediaBrowser.Model/LiveTv/RecommendedProgramQuery.cs b/MediaBrowser.Model/LiveTv/RecommendedProgramQuery.cs index 4a8ae2365b..09d45066b1 100644 --- a/MediaBrowser.Model/LiveTv/RecommendedProgramQuery.cs +++ b/MediaBrowser.Model/LiveTv/RecommendedProgramQuery.cs @@ -1,7 +1,19 @@ -namespace MediaBrowser.Model.LiveTv +using MediaBrowser.Model.Entities; +using MediaBrowser.Model.Querying; + +namespace MediaBrowser.Model.LiveTv { public class RecommendedProgramQuery { + /// <summary> + /// Fields to return within the items, in addition to basic information + /// </summary> + /// <value>The fields.</value> + public ItemFields[] Fields { get; set; } + public bool? EnableImages { get; set; } + public int? ImageTypeLimit { get; set; } + public ImageType[] EnableImageTypes { get; set; } + /// <summary> /// Gets or sets the user identifier. /// </summary> diff --git a/MediaBrowser.Model/LiveTv/RecordingQuery.cs b/MediaBrowser.Model/LiveTv/RecordingQuery.cs index daa137db64..0cf9976025 100644 --- a/MediaBrowser.Model/LiveTv/RecordingQuery.cs +++ b/MediaBrowser.Model/LiveTv/RecordingQuery.cs @@ -1,4 +1,7 @@ -namespace MediaBrowser.Model.LiveTv +using MediaBrowser.Model.Entities; +using MediaBrowser.Model.Querying; + +namespace MediaBrowser.Model.LiveTv { /// <summary> /// Class RecordingQuery. @@ -58,5 +61,14 @@ /// </summary> /// <value>The series timer identifier.</value> public string SeriesTimerId { get; set; } + + /// <summary> + /// Fields to return within the items, in addition to basic information + /// </summary> + /// <value>The fields.</value> + public ItemFields[] Fields { get; set; } + public bool? EnableImages { get; set; } + public int? ImageTypeLimit { get; set; } + public ImageType[] EnableImageTypes { get; set; } } } diff --git a/MediaBrowser.Server.Implementations/Dto/DtoService.cs b/MediaBrowser.Server.Implementations/Dto/DtoService.cs index 31f1b17dd1..2ff9a2813c 100644 --- a/MediaBrowser.Server.Implementations/Dto/DtoService.cs +++ b/MediaBrowser.Server.Implementations/Dto/DtoService.cs @@ -1767,11 +1767,6 @@ namespace MediaBrowser.Server.Implementations.Dto { size = _imageProcessor.GetImageSize(imageInfo); } - catch (FileNotFoundException) - { - _logger.Error("Image file does not exist: {0}", path); - return; - } catch (Exception ex) { _logger.ErrorException("Failed to determine primary image aspect ratio for {0}", ex, path); diff --git a/MediaBrowser.Server.Implementations/Library/MediaSourceManager.cs b/MediaBrowser.Server.Implementations/Library/MediaSourceManager.cs index 87e71e3278..2263b3e1f8 100644 --- a/MediaBrowser.Server.Implementations/Library/MediaSourceManager.cs +++ b/MediaBrowser.Server.Implementations/Library/MediaSourceManager.cs @@ -77,6 +77,10 @@ namespace MediaBrowser.Server.Implementations.Library { return false; } + if (string.Equals(stream.Codec, "ssa", StringComparison.OrdinalIgnoreCase)) + { + return false; + } return true; } diff --git a/MediaBrowser.Server.Implementations/LiveTv/LiveTvDtoService.cs b/MediaBrowser.Server.Implementations/LiveTv/LiveTvDtoService.cs index 72fea2c799..9ffd8a500e 100644 --- a/MediaBrowser.Server.Implementations/LiveTv/LiveTvDtoService.cs +++ b/MediaBrowser.Server.Implementations/LiveTv/LiveTvDtoService.cs @@ -198,10 +198,11 @@ namespace MediaBrowser.Server.Implementations.LiveTv /// Gets the channel info dto. /// </summary> /// <param name="info">The info.</param> + /// <param name="options">The options.</param> /// <param name="currentProgram">The current program.</param> /// <param name="user">The user.</param> /// <returns>ChannelInfoDto.</returns> - public ChannelInfoDto GetChannelInfoDto(LiveTvChannel info, LiveTvProgram currentProgram, User user = null) + public ChannelInfoDto GetChannelInfoDto(LiveTvChannel info, DtoOptions options, LiveTvProgram currentProgram, User user = null) { var dto = new ChannelInfoDto { @@ -238,7 +239,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv if (currentProgram != null) { - dto.CurrentProgram = _dtoService.GetBaseItemDto(currentProgram, new DtoOptions(), user); + dto.CurrentProgram = _dtoService.GetBaseItemDto(currentProgram, options, user); } return dto; diff --git a/MediaBrowser.Server.Implementations/LiveTv/LiveTvManager.cs b/MediaBrowser.Server.Implementations/LiveTv/LiveTvManager.cs index d8954724aa..f73e648fae 100644 --- a/MediaBrowser.Server.Implementations/LiveTv/LiveTvManager.cs +++ b/MediaBrowser.Server.Implementations/LiveTv/LiveTvManager.cs @@ -238,7 +238,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv return result; } - public async Task<QueryResult<ChannelInfoDto>> GetChannels(LiveTvChannelQuery query, CancellationToken cancellationToken) + public async Task<QueryResult<ChannelInfoDto>> GetChannels(LiveTvChannelQuery query, DtoOptions options, CancellationToken cancellationToken) { var user = string.IsNullOrEmpty(query.UserId) ? null : _userManager.GetUserById(query.UserId); @@ -261,7 +261,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv var channelIdString = channel.Id.ToString("N"); var currentProgram = programs.FirstOrDefault(i => string.Equals(i.ChannelId, channelIdString, StringComparison.OrdinalIgnoreCase)); - returnList.Add(_tvDtoService.GetChannelInfoDto(channel, currentProgram, user)); + returnList.Add(_tvDtoService.GetChannelInfoDto(channel, options, currentProgram, user)); } var result = new QueryResult<ChannelInfoDto> @@ -762,7 +762,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv return dto; } - public async Task<QueryResult<BaseItemDto>> GetPrograms(ProgramQuery query, CancellationToken cancellationToken) + public async Task<QueryResult<BaseItemDto>> GetPrograms(ProgramQuery query, DtoOptions options, CancellationToken cancellationToken) { var internalQuery = new InternalItemsQuery { @@ -822,7 +822,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv .Select(i => { RefreshIfNeeded(i); - return _dtoService.GetBaseItemDto(i, new DtoOptions(), user); + return _dtoService.GetBaseItemDto(i, options, user); }) .ToArray(); @@ -907,14 +907,14 @@ namespace MediaBrowser.Server.Implementations.LiveTv return result; } - public async Task<QueryResult<BaseItemDto>> GetRecommendedPrograms(RecommendedProgramQuery query, CancellationToken cancellationToken) + public async Task<QueryResult<BaseItemDto>> GetRecommendedPrograms(RecommendedProgramQuery query, DtoOptions options, CancellationToken cancellationToken) { var internalResult = await GetRecommendedProgramsInternal(query, cancellationToken).ConfigureAwait(false); var user = _userManager.GetUserById(query.UserId); var returnArray = internalResult.Items - .Select(i => _dtoService.GetBaseItemDto(i, new DtoOptions(), user)) + .Select(i => _dtoService.GetBaseItemDto(i, options, user)) .ToArray(); await AddRecordingInfo(returnArray, cancellationToken).ConfigureAwait(false); @@ -1712,7 +1712,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv .OrderBy(i => i.StartDate) .FirstOrDefault(); - var dto = _tvDtoService.GetChannelInfoDto(channel, currentProgram, user); + var dto = _tvDtoService.GetChannelInfoDto(channel, new DtoOptions(), currentProgram, user); return dto; } -- cgit v1.2.3 From 30710dbe007b60d696cdf28e4bf97a428432124b Mon Sep 17 00:00:00 2001 From: Luke Pulverenti <luke.pulverenti@gmail.com> Date: Tue, 4 Aug 2015 10:26:36 -0400 Subject: update components --- MediaBrowser.Api/LiveTv/LiveTvService.cs | 8 ++++++++ MediaBrowser.Model/Dto/BaseItemDto.cs | 1 + MediaBrowser.Model/LiveTv/ProgramQuery.cs | 5 +++++ MediaBrowser.Model/LiveTv/RecommendedProgramQuery.cs | 5 +++++ .../LiveTv/EmbyTV/EmbyTV.cs | 10 +++++----- .../LiveTv/Listings/SchedulesDirect.cs | 15 +++++++-------- .../LiveTv/LiveTvManager.cs | 4 +++- 7 files changed, 34 insertions(+), 14 deletions(-) (limited to 'MediaBrowser.Model/LiveTv') diff --git a/MediaBrowser.Api/LiveTv/LiveTvService.cs b/MediaBrowser.Api/LiveTv/LiveTvService.cs index 3ff4c4828e..bdec555611 100644 --- a/MediaBrowser.Api/LiveTv/LiveTvService.cs +++ b/MediaBrowser.Api/LiveTv/LiveTvService.cs @@ -222,6 +222,9 @@ namespace MediaBrowser.Api.LiveTv [ApiMember(Name = "IsMovie", Description = "Optional filter for movies.", IsRequired = false, DataType = "bool", ParameterType = "query", Verb = "GET,POST")] public bool? IsMovie { get; set; } + [ApiMember(Name = "IsKids", Description = "Optional filter for kids.", IsRequired = false, DataType = "bool", ParameterType = "query", Verb = "GET,POST")] + public bool? IsKids { get; set; } + [ApiMember(Name = "IsSports", Description = "Optional filter for sports.", IsRequired = false, DataType = "bool", ParameterType = "query", Verb = "GET,POST")] public bool? IsSports { get; set; } @@ -279,6 +282,9 @@ namespace MediaBrowser.Api.LiveTv [ApiMember(Name = "IsMovie", Description = "Optional filter for movies.", IsRequired = false, DataType = "bool", ParameterType = "query", Verb = "GET")] public bool? IsMovie { get; set; } + [ApiMember(Name = "IsKids", Description = "Optional filter for kids.", IsRequired = false, DataType = "bool", ParameterType = "query", Verb = "GET")] + public bool? IsKids { get; set; } + [ApiMember(Name = "EnableImages", Description = "Optional, include image information in output", IsRequired = false, DataType = "boolean", ParameterType = "query", Verb = "GET")] public bool? EnableImages { get; set; } @@ -607,6 +613,7 @@ namespace MediaBrowser.Api.LiveTv query.SortBy = (request.SortBy ?? String.Empty).Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries); query.SortOrder = request.SortOrder; query.IsMovie = request.IsMovie; + query.IsKids = request.IsKids; query.IsSports = request.IsSports; query.Genres = (request.Genres ?? String.Empty).Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries); @@ -624,6 +631,7 @@ namespace MediaBrowser.Api.LiveTv Limit = request.Limit, HasAired = request.HasAired, IsMovie = request.IsMovie, + IsKids = request.IsKids, IsSports = request.IsSports }; diff --git a/MediaBrowser.Model/Dto/BaseItemDto.cs b/MediaBrowser.Model/Dto/BaseItemDto.cs index 7c5d9e9a11..aa68e09a0f 100644 --- a/MediaBrowser.Model/Dto/BaseItemDto.cs +++ b/MediaBrowser.Model/Dto/BaseItemDto.cs @@ -646,6 +646,7 @@ namespace MediaBrowser.Model.Dto /// Gets or sets a value indicating whether [supports playlists]. /// </summary> /// <value><c>true</c> if [supports playlists]; otherwise, <c>false</c>.</value> + [IgnoreDataMember] public bool SupportsPlaylists { get diff --git a/MediaBrowser.Model/LiveTv/ProgramQuery.cs b/MediaBrowser.Model/LiveTv/ProgramQuery.cs index 3f652ea6f5..7a877e3561 100644 --- a/MediaBrowser.Model/LiveTv/ProgramQuery.cs +++ b/MediaBrowser.Model/LiveTv/ProgramQuery.cs @@ -63,6 +63,11 @@ namespace MediaBrowser.Model.LiveTv /// <remarks>If set to null, all programs will be returned</remarks> public bool? IsMovie { get; set; } + /// <summary> + /// Gets or sets a value indicating whether this instance is kids. + /// </summary> + /// <value><c>null</c> if [is kids] contains no value, <c>true</c> if [is kids]; otherwise, <c>false</c>.</value> + public bool? IsKids { get; set; } /// <summary> /// Gets or sets a value indicating whether this instance is sports. /// </summary> diff --git a/MediaBrowser.Model/LiveTv/RecommendedProgramQuery.cs b/MediaBrowser.Model/LiveTv/RecommendedProgramQuery.cs index 09d45066b1..e83a8fda65 100644 --- a/MediaBrowser.Model/LiveTv/RecommendedProgramQuery.cs +++ b/MediaBrowser.Model/LiveTv/RecommendedProgramQuery.cs @@ -44,6 +44,11 @@ namespace MediaBrowser.Model.LiveTv /// <value><c>null</c> if [is movie] contains no value, <c>true</c> if [is movie]; otherwise, <c>false</c>.</value> public bool? IsMovie { get; set; } /// <summary> + /// Gets or sets a value indicating whether this instance is kids. + /// </summary> + /// <value><c>null</c> if [is kids] contains no value, <c>true</c> if [is kids]; otherwise, <c>false</c>.</value> + public bool? IsKids { get; set; } + /// <summary> /// Gets or sets a value indicating whether this instance is sports. /// </summary> /// <value><c>null</c> if [is sports] contains no value, <c>true</c> if [is sports]; otherwise, <c>false</c>.</value> diff --git a/MediaBrowser.Server.Implementations/LiveTv/EmbyTV/EmbyTV.cs b/MediaBrowser.Server.Implementations/LiveTv/EmbyTV/EmbyTV.cs index 9ca2537f14..b96e3b26c1 100644 --- a/MediaBrowser.Server.Implementations/LiveTv/EmbyTV/EmbyTV.cs +++ b/MediaBrowser.Server.Implementations/LiveTv/EmbyTV/EmbyTV.cs @@ -490,13 +490,13 @@ namespace MediaBrowser.Server.Implementations.LiveTv.EmbyTV if (recording == null) { - recording = new RecordingInfo() + recording = new RecordingInfo { ChannelId = info.ChannelId, Id = Guid.NewGuid().ToString("N"), StartDate = info.StartDate, EndDate = info.EndDate, - Genres = info.Genres ?? null, + Genres = info.Genres, IsKids = info.IsKids, IsLive = info.IsLive, IsMovie = info.IsMovie, @@ -507,10 +507,10 @@ namespace MediaBrowser.Server.Implementations.LiveTv.EmbyTV IsSports = info.IsSports, IsRepeat = !info.IsPremiere, Name = info.Name, - EpisodeTitle = info.EpisodeTitle ?? "", + EpisodeTitle = info.EpisodeTitle, ProgramId = info.Id, - HasImage = info.HasImage ?? false, - ImagePath = info.ImagePath ?? null, + HasImage = info.HasImage, + ImagePath = info.ImagePath, ImageUrl = info.ImageUrl, OriginalAirDate = info.OriginalAirDate, Status = RecordingStatus.Scheduled, diff --git a/MediaBrowser.Server.Implementations/LiveTv/Listings/SchedulesDirect.cs b/MediaBrowser.Server.Implementations/LiveTv/Listings/SchedulesDirect.cs index 655feedae3..2aadf4a665 100644 --- a/MediaBrowser.Server.Implementations/LiveTv/Listings/SchedulesDirect.cs +++ b/MediaBrowser.Server.Implementations/LiveTv/Listings/SchedulesDirect.cs @@ -286,20 +286,20 @@ namespace MediaBrowser.Server.Implementations.LiveTv.Listings } } ScheduleDirect.Gracenote gracenote; - string EpisodeTitle = ""; + string episodeTitle = null; if (details.metadata != null) { gracenote = details.metadata.Find(x => x.Gracenote != null).Gracenote; if ((details.showType ?? "No ShowType") == "Series") { - EpisodeTitle = "Season: " + gracenote.season + " Episode: " + gracenote.episode; + episodeTitle = "Season: " + gracenote.season + " Episode: " + gracenote.episode; } } if (details.episodeTitle150 != null) { - EpisodeTitle = EpisodeTitle + " " + details.episodeTitle150; + episodeTitle = ((episodeTitle ?? string.Empty) + " " + details.episodeTitle150).Trim(); } - bool hasImage = false; + var imageLink = ""; if (details.hasImageArtwork) @@ -314,11 +314,10 @@ namespace MediaBrowser.Server.Implementations.LiveTv.Listings Overview = desc, StartDate = startAt, EndDate = endAt, - Genres = new List<string>() { "N/A" }, Name = details.titles[0].title120 ?? "Unkown", OfficialRating = "0", CommunityRating = null, - EpisodeTitle = EpisodeTitle, + EpisodeTitle = episodeTitle, Audio = audioType, IsHD = hdtv, IsRepeat = repeat, @@ -339,8 +338,8 @@ namespace MediaBrowser.Server.Implementations.LiveTv.Listings (details.showType ?? "No ShowType") == "Short Film", IsPremiere = false, }; - //logger.Info("Done init"); - if (null != details.originalAirDate) + + if (!string.IsNullOrWhiteSpace(details.originalAirDate)) { info.OriginalAirDate = DateTime.Parse(details.originalAirDate); } diff --git a/MediaBrowser.Server.Implementations/LiveTv/LiveTvManager.cs b/MediaBrowser.Server.Implementations/LiveTv/LiveTvManager.cs index b4669f53eb..6861901ac8 100644 --- a/MediaBrowser.Server.Implementations/LiveTv/LiveTvManager.cs +++ b/MediaBrowser.Server.Implementations/LiveTv/LiveTvManager.cs @@ -774,6 +774,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv ChannelIds = query.ChannelIds, IsMovie = query.IsMovie, IsSports = query.IsSports, + IsKids = query.IsKids, Genres = query.Genres }; @@ -844,7 +845,8 @@ namespace MediaBrowser.Server.Implementations.LiveTv IncludeItemTypes = new[] { typeof(LiveTvProgram).Name }, IsAiring = query.IsAiring, IsMovie = query.IsMovie, - IsSports = query.IsSports + IsSports = query.IsSports, + IsKids = query.IsKids }; if (query.HasAired.HasValue) -- cgit v1.2.3 From f49417c703802a646910476dab38dc3f1adfb5c3 Mon Sep 17 00:00:00 2001 From: Luke Pulverenti <luke.pulverenti@gmail.com> Date: Sun, 16 Aug 2015 16:26:49 -0400 Subject: update series recordings --- MediaBrowser.Controller/LiveTv/LiveTvProgram.cs | 6 ++++++ MediaBrowser.Model/LiveTv/SeriesTimerInfoDto.cs | 9 +++++++++ MediaBrowser.Server.Implementations/LiveTv/EmbyTV/EmbyTV.cs | 2 +- MediaBrowser.Server.Implementations/LiveTv/LiveTvDtoService.cs | 6 ++++-- MediaBrowser.Server.Implementations/LiveTv/LiveTvManager.cs | 5 ++++- .../LiveTv/TunerHosts/HdHomerun/HdHomerunHost.cs | 2 ++ 6 files changed, 26 insertions(+), 4 deletions(-) (limited to 'MediaBrowser.Model/LiveTv') diff --git a/MediaBrowser.Controller/LiveTv/LiveTvProgram.cs b/MediaBrowser.Controller/LiveTv/LiveTvProgram.cs index b54a7aaeeb..0a1735c238 100644 --- a/MediaBrowser.Controller/LiveTv/LiveTvProgram.cs +++ b/MediaBrowser.Controller/LiveTv/LiveTvProgram.cs @@ -60,6 +60,12 @@ namespace MediaBrowser.Controller.LiveTv /// <value><c>true</c> if this instance is repeat; otherwise, <c>false</c>.</value> public bool IsRepeat { get; set; } + /// <summary> + /// Gets or sets the external series identifier. + /// </summary> + /// <value>The external series identifier.</value> + public string ExternalSeriesId { get; set; } + /// <summary> /// Gets or sets the episode title. /// </summary> diff --git a/MediaBrowser.Model/LiveTv/SeriesTimerInfoDto.cs b/MediaBrowser.Model/LiveTv/SeriesTimerInfoDto.cs index 7c590307fb..70c6892ef2 100644 --- a/MediaBrowser.Model/LiveTv/SeriesTimerInfoDto.cs +++ b/MediaBrowser.Model/LiveTv/SeriesTimerInfoDto.cs @@ -6,6 +6,9 @@ using System.Runtime.Serialization; namespace MediaBrowser.Model.LiveTv { + /// <summary> + /// Class SeriesTimerInfoDto. + /// </summary> [DebuggerDisplay("Name = {Name}")] public class SeriesTimerInfoDto : BaseTimerInfoDto { @@ -45,6 +48,12 @@ namespace MediaBrowser.Model.LiveTv /// <value>The image tags.</value> public Dictionary<ImageType, string> ImageTags { get; set; } + /// <summary> + /// Gets or sets the external series identifier. + /// </summary> + /// <value>The external series identifier.</value> + public string ExternalSeriesId { get; set; } + /// <summary> /// Gets a value indicating whether this instance has primary image. /// </summary> diff --git a/MediaBrowser.Server.Implementations/LiveTv/EmbyTV/EmbyTV.cs b/MediaBrowser.Server.Implementations/LiveTv/EmbyTV/EmbyTV.cs index 9ff8f72064..177a64ddc5 100644 --- a/MediaBrowser.Server.Implementations/LiveTv/EmbyTV/EmbyTV.cs +++ b/MediaBrowser.Server.Implementations/LiveTv/EmbyTV/EmbyTV.cs @@ -220,7 +220,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv.EmbyTV if (enableDelay) { // A hack yes, but need to make sure the file is closed before attempting to delete it - await Task.Delay(3000).ConfigureAwait(false); + await Task.Delay(3000, cancellationToken).ConfigureAwait(false); } } diff --git a/MediaBrowser.Server.Implementations/LiveTv/LiveTvDtoService.cs b/MediaBrowser.Server.Implementations/LiveTv/LiveTvDtoService.cs index 9ffd8a500e..2587b10059 100644 --- a/MediaBrowser.Server.Implementations/LiveTv/LiveTvDtoService.cs +++ b/MediaBrowser.Server.Implementations/LiveTv/LiveTvDtoService.cs @@ -105,7 +105,8 @@ namespace MediaBrowser.Server.Implementations.LiveTv ExternalProgramId = info.ProgramId, ServiceName = service.Name, ChannelName = channelName, - ServerId = _appHost.SystemId + ServerId = _appHost.SystemId, + ExternalSeriesId = info.SeriesId }; if (!string.IsNullOrEmpty(info.ChannelId)) @@ -376,7 +377,8 @@ namespace MediaBrowser.Server.Implementations.LiveTv RecordNewOnly = dto.RecordNewOnly, ProgramId = dto.ExternalProgramId, ChannelId = dto.ExternalChannelId, - Id = dto.ExternalId + Id = dto.ExternalId, + SeriesId = dto.ExternalSeriesId }; // Convert internal server id's to external tv provider id's diff --git a/MediaBrowser.Server.Implementations/LiveTv/LiveTvManager.cs b/MediaBrowser.Server.Implementations/LiveTv/LiveTvManager.cs index 782473bea6..9065a8ac2a 100644 --- a/MediaBrowser.Server.Implementations/LiveTv/LiveTvManager.cs +++ b/MediaBrowser.Server.Implementations/LiveTv/LiveTvManager.cs @@ -627,6 +627,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv item.ProductionYear = info.ProductionYear; item.PremiereDate = item.PremiereDate ?? info.OriginalAirDate; + item.ExternalSeriesId = info.SeriesId; if (isNew) { @@ -1786,7 +1787,8 @@ namespace MediaBrowser.Server.Implementations.LiveTv ImagePath = program.ProviderImagePath, ImageUrl = program.ProviderImageUrl, Name = program.Name, - OfficialRating = program.OfficialRating + OfficialRating = program.OfficialRating, + SeriesId = program.ExternalSeriesId }; } @@ -1829,6 +1831,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv info.Overview = program.Overview; info.ProgramId = programDto.Id; info.ExternalProgramId = program.ExternalId; + info.ExternalSeriesId = program.ExternalSeriesId; if (program.EndDate.HasValue) { diff --git a/MediaBrowser.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunHost.cs b/MediaBrowser.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunHost.cs index b09f8cfef5..35f77abcb6 100644 --- a/MediaBrowser.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunHost.cs +++ b/MediaBrowser.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunHost.cs @@ -326,6 +326,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv.TunerHosts.HdHomerun { return list; } + channelId = channelId.Substring(ChannelIdPrefix.Length); list.Add(GetMediaSource(info, channelId, "native")); @@ -358,6 +359,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv.TunerHosts.HdHomerun { return null; } + channelId = channelId.Substring(ChannelIdPrefix.Length); return GetMediaSource(info, channelId, streamId); } -- cgit v1.2.3 From 90843b218c9174b8697ddaa296594f9d364fa388 Mon Sep 17 00:00:00 2001 From: Luke Pulverenti <luke.pulverenti@gmail.com> Date: Sun, 16 Aug 2015 18:03:22 -0400 Subject: update recording styles --- MediaBrowser.Controller/LiveTv/LiveTvProgram.cs | 6 --- MediaBrowser.Model/LiveTv/SeriesTimerInfoDto.cs | 6 --- .../LiveTv/EmbyTV/EmbyTV.cs | 54 ++++++++++++++++------ .../LiveTv/LiveTvDtoService.cs | 6 +-- .../LiveTv/LiveTvManager.cs | 5 +- 5 files changed, 42 insertions(+), 35 deletions(-) (limited to 'MediaBrowser.Model/LiveTv') diff --git a/MediaBrowser.Controller/LiveTv/LiveTvProgram.cs b/MediaBrowser.Controller/LiveTv/LiveTvProgram.cs index 0a1735c238..b54a7aaeeb 100644 --- a/MediaBrowser.Controller/LiveTv/LiveTvProgram.cs +++ b/MediaBrowser.Controller/LiveTv/LiveTvProgram.cs @@ -60,12 +60,6 @@ namespace MediaBrowser.Controller.LiveTv /// <value><c>true</c> if this instance is repeat; otherwise, <c>false</c>.</value> public bool IsRepeat { get; set; } - /// <summary> - /// Gets or sets the external series identifier. - /// </summary> - /// <value>The external series identifier.</value> - public string ExternalSeriesId { get; set; } - /// <summary> /// Gets or sets the episode title. /// </summary> diff --git a/MediaBrowser.Model/LiveTv/SeriesTimerInfoDto.cs b/MediaBrowser.Model/LiveTv/SeriesTimerInfoDto.cs index 70c6892ef2..4b88e42f31 100644 --- a/MediaBrowser.Model/LiveTv/SeriesTimerInfoDto.cs +++ b/MediaBrowser.Model/LiveTv/SeriesTimerInfoDto.cs @@ -48,12 +48,6 @@ namespace MediaBrowser.Model.LiveTv /// <value>The image tags.</value> public Dictionary<ImageType, string> ImageTags { get; set; } - /// <summary> - /// Gets or sets the external series identifier. - /// </summary> - /// <value>The external series identifier.</value> - public string ExternalSeriesId { get; set; } - /// <summary> /// Gets a value indicating whether this instance has primary image. /// </summary> diff --git a/MediaBrowser.Server.Implementations/LiveTv/EmbyTV/EmbyTV.cs b/MediaBrowser.Server.Implementations/LiveTv/EmbyTV/EmbyTV.cs index 177a64ddc5..7273ac88ec 100644 --- a/MediaBrowser.Server.Implementations/LiveTv/EmbyTV/EmbyTV.cs +++ b/MediaBrowser.Server.Implementations/LiveTv/EmbyTV/EmbyTV.cs @@ -251,14 +251,50 @@ namespace MediaBrowser.Server.Implementations.LiveTv.EmbyTV { info.Id = Guid.NewGuid().ToString("N"); - await UpdateTimersForSeriesTimer(info).ConfigureAwait(false); + List<ProgramInfo> epgData; + if (info.RecordAnyChannel) + { + var channels = await GetChannelsAsync(true, CancellationToken.None).ConfigureAwait(false); + var channelIds = channels.Select(i => i.Id).ToList(); + epgData = GetEpgDataForChannels(channelIds); + } + else + { + epgData = GetEpgDataForChannel(info.ChannelId); + } + + // populate info.seriesID + var program = epgData.FirstOrDefault(i => string.Equals(i.Id, info.ProgramId, StringComparison.OrdinalIgnoreCase)); + + if (program != null) + { + info.SeriesId = program.SeriesId; + } + else + { + throw new InvalidOperationException("SeriesId for program not found"); + } + _seriesTimerProvider.Add(info); + await UpdateTimersForSeriesTimer(epgData, info).ConfigureAwait(false); } public async Task UpdateSeriesTimerAsync(SeriesTimerInfo info, CancellationToken cancellationToken) { _seriesTimerProvider.Update(info); - await UpdateTimersForSeriesTimer(info).ConfigureAwait(false); + List<ProgramInfo> epgData; + if (info.RecordAnyChannel) + { + var channels = await GetChannelsAsync(true, CancellationToken.None).ConfigureAwait(false); + var channelIds = channels.Select(i => i.Id).ToList(); + epgData = GetEpgDataForChannels(channelIds); + } + else + { + epgData = GetEpgDataForChannel(info.ChannelId); + } + + await UpdateTimersForSeriesTimer(epgData, info).ConfigureAwait(false); } public Task UpdateTimerAsync(TimerInfo info, CancellationToken cancellationToken) @@ -597,20 +633,8 @@ namespace MediaBrowser.Server.Implementations.LiveTv.EmbyTV return _config.GetConfiguration<LiveTvOptions>("livetv"); } - private async Task UpdateTimersForSeriesTimer(SeriesTimerInfo seriesTimer) + private async Task UpdateTimersForSeriesTimer(List<ProgramInfo> epgData, SeriesTimerInfo seriesTimer) { - List<ProgramInfo> epgData; - if (seriesTimer.RecordAnyChannel) - { - var channels = await GetChannelsAsync(true, CancellationToken.None).ConfigureAwait(false); - var channelIds = channels.Select(i => i.Id).ToList(); - epgData = GetEpgDataForChannels(channelIds); - } - else - { - epgData = GetEpgDataForChannel(seriesTimer.ChannelId); - } - var newTimers = GetTimersForSeries(seriesTimer, epgData, _recordingProvider.GetAll()).ToList(); var existingTimers = _timerProvider.GetAll() diff --git a/MediaBrowser.Server.Implementations/LiveTv/LiveTvDtoService.cs b/MediaBrowser.Server.Implementations/LiveTv/LiveTvDtoService.cs index 2587b10059..9ffd8a500e 100644 --- a/MediaBrowser.Server.Implementations/LiveTv/LiveTvDtoService.cs +++ b/MediaBrowser.Server.Implementations/LiveTv/LiveTvDtoService.cs @@ -105,8 +105,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv ExternalProgramId = info.ProgramId, ServiceName = service.Name, ChannelName = channelName, - ServerId = _appHost.SystemId, - ExternalSeriesId = info.SeriesId + ServerId = _appHost.SystemId }; if (!string.IsNullOrEmpty(info.ChannelId)) @@ -377,8 +376,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv RecordNewOnly = dto.RecordNewOnly, ProgramId = dto.ExternalProgramId, ChannelId = dto.ExternalChannelId, - Id = dto.ExternalId, - SeriesId = dto.ExternalSeriesId + Id = dto.ExternalId }; // Convert internal server id's to external tv provider id's diff --git a/MediaBrowser.Server.Implementations/LiveTv/LiveTvManager.cs b/MediaBrowser.Server.Implementations/LiveTv/LiveTvManager.cs index 9065a8ac2a..782473bea6 100644 --- a/MediaBrowser.Server.Implementations/LiveTv/LiveTvManager.cs +++ b/MediaBrowser.Server.Implementations/LiveTv/LiveTvManager.cs @@ -627,7 +627,6 @@ namespace MediaBrowser.Server.Implementations.LiveTv item.ProductionYear = info.ProductionYear; item.PremiereDate = item.PremiereDate ?? info.OriginalAirDate; - item.ExternalSeriesId = info.SeriesId; if (isNew) { @@ -1787,8 +1786,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv ImagePath = program.ProviderImagePath, ImageUrl = program.ProviderImageUrl, Name = program.Name, - OfficialRating = program.OfficialRating, - SeriesId = program.ExternalSeriesId + OfficialRating = program.OfficialRating }; } @@ -1831,7 +1829,6 @@ namespace MediaBrowser.Server.Implementations.LiveTv info.Overview = program.Overview; info.ProgramId = programDto.Id; info.ExternalProgramId = program.ExternalId; - info.ExternalSeriesId = program.ExternalSeriesId; if (program.EndDate.HasValue) { -- cgit v1.2.3 From 795a8ab33b6a8937ee7c6c4d3524d4a8b1e2ba33 Mon Sep 17 00:00:00 2001 From: Luke Pulverenti <luke.pulverenti@gmail.com> Date: Sat, 22 Aug 2015 15:46:55 -0400 Subject: added auto-organize setting --- MediaBrowser.Model/LiveTv/LiveTvOptions.cs | 1 + .../FileOrganization/EpisodeFileOrganizer.cs | 11 ++++- .../FileOrganization/TvFolderOrganizer.cs | 15 +------ .../LiveTv/EmbyTV/EmbyTV.cs | 51 ++++++++++++++++++++-- 4 files changed, 59 insertions(+), 19 deletions(-) (limited to 'MediaBrowser.Model/LiveTv') diff --git a/MediaBrowser.Model/LiveTv/LiveTvOptions.cs b/MediaBrowser.Model/LiveTv/LiveTvOptions.cs index c5e8f46366..7881231a20 100644 --- a/MediaBrowser.Model/LiveTv/LiveTvOptions.cs +++ b/MediaBrowser.Model/LiveTv/LiveTvOptions.cs @@ -7,6 +7,7 @@ namespace MediaBrowser.Model.LiveTv public int? GuideDays { get; set; } public bool EnableMovieProviders { get; set; } public string RecordingPath { get; set; } + public bool EnableAutoOrganize { get; set; } public List<TunerHostInfo> TunerHosts { get; set; } public List<ListingsProviderInfo> ListingProviders { get; set; } diff --git a/MediaBrowser.Server.Implementations/FileOrganization/EpisodeFileOrganizer.cs b/MediaBrowser.Server.Implementations/FileOrganization/EpisodeFileOrganizer.cs index e134670e39..06b72e4ef4 100644 --- a/MediaBrowser.Server.Implementations/FileOrganization/EpisodeFileOrganizer.cs +++ b/MediaBrowser.Server.Implementations/FileOrganization/EpisodeFileOrganizer.cs @@ -43,6 +43,13 @@ namespace MediaBrowser.Server.Implementations.FileOrganization _providerManager = providerManager; } + public Task<FileOrganizationResult> OrganizeEpisodeFile(string path, CancellationToken cancellationToken) + { + var options = _config.GetAutoOrganizeOptions().TvOptions; + + return OrganizeEpisodeFile(path, options, false, cancellationToken); + } + public async Task<FileOrganizationResult> OrganizeEpisodeFile(string path, TvFileOrganizationOptions options, bool overwriteExisting, CancellationToken cancellationToken) { _logger.Info("Sorting file {0}", path); @@ -56,7 +63,7 @@ namespace MediaBrowser.Server.Implementations.FileOrganization FileSize = new FileInfo(path).Length }; - var namingOptions = ((LibraryManager) _libraryManager).GetNamingOptions(); + var namingOptions = ((LibraryManager)_libraryManager).GetNamingOptions(); var resolver = new Naming.TV.EpisodeResolver(namingOptions, new PatternsLogger()); var episodeInfo = resolver.Resolve(path, false) ?? @@ -254,7 +261,7 @@ namespace MediaBrowser.Server.Implementations.FileOrganization .ToList(); var targetFilenameWithoutExtension = Path.GetFileNameWithoutExtension(targetPath); - + foreach (var file in files) { directory = Path.GetDirectoryName(file); diff --git a/MediaBrowser.Server.Implementations/FileOrganization/TvFolderOrganizer.cs b/MediaBrowser.Server.Implementations/FileOrganization/TvFolderOrganizer.cs index 557b531b43..0caa8c26e4 100644 --- a/MediaBrowser.Server.Implementations/FileOrganization/TvFolderOrganizer.cs +++ b/MediaBrowser.Server.Implementations/FileOrganization/TvFolderOrganizer.cs @@ -48,8 +48,6 @@ namespace MediaBrowser.Server.Implementations.FileOrganization progress.Report(10); - var scanLibrary = false; - if (eligibleFiles.Count > 0) { var numComplete = 0; @@ -61,12 +59,7 @@ namespace MediaBrowser.Server.Implementations.FileOrganization try { - var result = await organizer.OrganizeEpisodeFile(file.FullName, options, options.OverwriteExistingEpisodes, cancellationToken).ConfigureAwait(false); - - if (result.Status == FileSortingStatus.Success) - { - scanLibrary = true; - } + await organizer.OrganizeEpisodeFile(file.FullName, options, options.OverwriteExistingEpisodes, cancellationToken).ConfigureAwait(false); } catch (Exception ex) { @@ -106,12 +99,6 @@ namespace MediaBrowser.Server.Implementations.FileOrganization } } - if (scanLibrary) - { - await _libraryManager.ValidateMediaLibrary(new Progress<double>(), CancellationToken.None) - .ConfigureAwait(false); - } - progress.Report(100); } diff --git a/MediaBrowser.Server.Implementations/LiveTv/EmbyTV/EmbyTV.cs b/MediaBrowser.Server.Implementations/LiveTv/EmbyTV/EmbyTV.cs index 2f1b9d03e4..96e14a21c3 100644 --- a/MediaBrowser.Server.Implementations/LiveTv/EmbyTV/EmbyTV.cs +++ b/MediaBrowser.Server.Implementations/LiveTv/EmbyTV/EmbyTV.cs @@ -3,14 +3,20 @@ using MediaBrowser.Common.Configuration; using MediaBrowser.Common.IO; using MediaBrowser.Common.Net; using MediaBrowser.Common.Security; +using MediaBrowser.Controller.Configuration; using MediaBrowser.Controller.Drawing; +using MediaBrowser.Controller.FileOrganization; +using MediaBrowser.Controller.Library; using MediaBrowser.Controller.LiveTv; +using MediaBrowser.Controller.Providers; using MediaBrowser.Model.Dto; using MediaBrowser.Model.Entities; using MediaBrowser.Model.Events; +using MediaBrowser.Model.FileOrganization; using MediaBrowser.Model.LiveTv; using MediaBrowser.Model.Logging; using MediaBrowser.Model.Serialization; +using MediaBrowser.Server.Implementations.FileOrganization; using System; using System.Collections.Concurrent; using System.Collections.Generic; @@ -21,12 +27,12 @@ using System.Threading.Tasks; namespace MediaBrowser.Server.Implementations.LiveTv.EmbyTV { - public class EmbyTV : ILiveTvService/*, IHasRegistrationInfo*/, IDisposable + public class EmbyTV : ILiveTvService, IHasRegistrationInfo, IDisposable { private readonly IApplicationHost _appHpst; private readonly ILogger _logger; private readonly IHttpClient _httpClient; - private readonly IConfigurationManager _config; + private readonly IServerConfigurationManager _config; private readonly IJsonSerializer _jsonSerializer; private readonly ItemDataProvider<RecordingInfo> _recordingProvider; @@ -37,9 +43,14 @@ namespace MediaBrowser.Server.Implementations.LiveTv.EmbyTV private readonly IFileSystem _fileSystem; private readonly ISecurityManager _security; + private readonly ILibraryMonitor _libraryMonitor; + private readonly ILibraryManager _libraryManager; + private readonly IProviderManager _providerManager; + private readonly IFileOrganizationService _organizationService; + public static EmbyTV Current; - public EmbyTV(IApplicationHost appHost, ILogger logger, IJsonSerializer jsonSerializer, IHttpClient httpClient, IConfigurationManager config, ILiveTvManager liveTvManager, IFileSystem fileSystem, ISecurityManager security) + public EmbyTV(IApplicationHost appHost, ILogger logger, IJsonSerializer jsonSerializer, IHttpClient httpClient, IServerConfigurationManager config, ILiveTvManager liveTvManager, IFileSystem fileSystem, ISecurityManager security, ILibraryManager libraryManager, ILibraryMonitor libraryMonitor, IProviderManager providerManager, IFileOrganizationService organizationService) { Current = this; @@ -49,6 +60,10 @@ namespace MediaBrowser.Server.Implementations.LiveTv.EmbyTV _config = config; _fileSystem = fileSystem; _security = security; + _libraryManager = libraryManager; + _libraryMonitor = libraryMonitor; + _providerManager = providerManager; + _organizationService = organizationService; _liveTvManager = (LiveTvManager)liveTvManager; _jsonSerializer = jsonSerializer; @@ -610,6 +625,36 @@ namespace MediaBrowser.Server.Implementations.LiveTv.EmbyTV _recordingProvider.Update(recording); _timerProvider.Delete(timer); _logger.Info("Recording was a success"); + + if (recording.Status == RecordingStatus.Completed) + { + OnSuccessfulRecording(recording); + } + } + + private async void OnSuccessfulRecording(RecordingInfo recording) + { + if (GetConfiguration().EnableAutoOrganize) + { + if (recording.IsSeries) + { + try + { + var organize = new EpisodeFileOrganizer(_organizationService, _config, _fileSystem, _logger, _libraryManager, _libraryMonitor, _providerManager); + + var result = await organize.OrganizeEpisodeFile(recording.Path, CancellationToken.None).ConfigureAwait(false); + + if (result.Status == FileSortingStatus.Success) + { + _recordingProvider.Delete(recording); + } + } + catch (Exception ex) + { + _logger.ErrorException("Error processing new recording", ex); + } + } + } } private ProgramInfo GetProgramInfoFromCache(string channelId, string programId) -- cgit v1.2.3 From 474cbbb87a51cb0fe82c408789c75b3971b58227 Mon Sep 17 00:00:00 2001 From: Luke Pulverenti <luke.pulverenti@gmail.com> Date: Sun, 23 Aug 2015 22:08:20 -0400 Subject: added default padding settings --- MediaBrowser.Model/LiveTv/LiveTvOptions.cs | 5 ++++- .../Library/LibraryManager.cs | 2 +- .../Library/MediaSourceManager.cs | 5 ++++- MediaBrowser.Server.Implementations/LiveTv/EmbyTV/EmbyTV.cs | 6 ++++-- MediaBrowser.Server.Implementations/LiveTv/LiveTvManager.cs | 3 +-- .../LiveTv/LiveTvMediaSourceProvider.cs | 7 ++++++- .../LiveTv/TunerHosts/HdHomerun/HdHomerunHost.cs | 13 +++++++++++-- SharedVersion.cs | 4 ++-- 8 files changed, 33 insertions(+), 12 deletions(-) (limited to 'MediaBrowser.Model/LiveTv') diff --git a/MediaBrowser.Model/LiveTv/LiveTvOptions.cs b/MediaBrowser.Model/LiveTv/LiveTvOptions.cs index 7881231a20..2b45422ec3 100644 --- a/MediaBrowser.Model/LiveTv/LiveTvOptions.cs +++ b/MediaBrowser.Model/LiveTv/LiveTvOptions.cs @@ -11,7 +11,10 @@ namespace MediaBrowser.Model.LiveTv public List<TunerHostInfo> TunerHosts { get; set; } public List<ListingsProviderInfo> ListingProviders { get; set; } - + + public int PrePaddingSeconds { get; set; } + public int PostPaddingSeconds { get; set; } + public LiveTvOptions() { EnableMovieProviders = true; diff --git a/MediaBrowser.Server.Implementations/Library/LibraryManager.cs b/MediaBrowser.Server.Implementations/Library/LibraryManager.cs index a67e3d7329..cc9d9551c2 100644 --- a/MediaBrowser.Server.Implementations/Library/LibraryManager.cs +++ b/MediaBrowser.Server.Implementations/Library/LibraryManager.cs @@ -937,7 +937,7 @@ namespace MediaBrowser.Server.Implementations.Library (item as MusicArtist).IsAccessedByName = true; } - var task = item.UpdateToRepository(ItemUpdateType.None, CancellationToken.None); + var task = CreateItem(item, CancellationToken.None); Task.WaitAll(task); } diff --git a/MediaBrowser.Server.Implementations/Library/MediaSourceManager.cs b/MediaBrowser.Server.Implementations/Library/MediaSourceManager.cs index c5ff100f9d..1f4dff2775 100644 --- a/MediaBrowser.Server.Implementations/Library/MediaSourceManager.cs +++ b/MediaBrowser.Server.Implementations/Library/MediaSourceManager.cs @@ -483,7 +483,10 @@ namespace MediaBrowser.Server.Implementations.Library var provider = _providers.FirstOrDefault(i => string.Equals(i.GetType().FullName.GetMD5().ToString("N"), keys[0], StringComparison.OrdinalIgnoreCase)); - return new Tuple<IMediaSourceProvider, string>(provider, keys[1]); + var splitIndex = key.IndexOf(LiveStreamIdDelimeter); + var keyId = key.Substring(splitIndex + 1); + + return new Tuple<IMediaSourceProvider, string>(provider, keyId); } private Timer _closeTimer; diff --git a/MediaBrowser.Server.Implementations/LiveTv/EmbyTV/EmbyTV.cs b/MediaBrowser.Server.Implementations/LiveTv/EmbyTV/EmbyTV.cs index 96e14a21c3..b69cdacef3 100644 --- a/MediaBrowser.Server.Implementations/LiveTv/EmbyTV/EmbyTV.cs +++ b/MediaBrowser.Server.Implementations/LiveTv/EmbyTV/EmbyTV.cs @@ -339,10 +339,12 @@ namespace MediaBrowser.Server.Implementations.LiveTv.EmbyTV public Task<SeriesTimerInfo> GetNewTimerDefaultsAsync(CancellationToken cancellationToken, ProgramInfo program = null) { + var config = GetConfiguration(); + var defaults = new SeriesTimerInfo() { - PostPaddingSeconds = 0, - PrePaddingSeconds = 0, + PostPaddingSeconds = Math.Max(config.PostPaddingSeconds, 0), + PrePaddingSeconds = Math.Max(config.PrePaddingSeconds, 0), RecordAnyChannel = false, RecordAnyTime = false, RecordNewOnly = false diff --git a/MediaBrowser.Server.Implementations/LiveTv/LiveTvManager.cs b/MediaBrowser.Server.Implementations/LiveTv/LiveTvManager.cs index 1721d6101e..653adb7163 100644 --- a/MediaBrowser.Server.Implementations/LiveTv/LiveTvManager.cs +++ b/MediaBrowser.Server.Implementations/LiveTv/LiveTvManager.cs @@ -889,8 +889,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv if (query.Limit.HasValue) { - programs = programs.Take(query.Limit.Value) - .OrderBy(i => i.StartDate); + programs = programs.Take(query.Limit.Value); } programList = programs.ToList(); diff --git a/MediaBrowser.Server.Implementations/LiveTv/LiveTvMediaSourceProvider.cs b/MediaBrowser.Server.Implementations/LiveTv/LiveTvMediaSourceProvider.cs index 66a21830e8..d9d9b76b99 100644 --- a/MediaBrowser.Server.Implementations/LiveTv/LiveTvMediaSourceProvider.cs +++ b/MediaBrowser.Server.Implementations/LiveTv/LiveTvMediaSourceProvider.cs @@ -125,7 +125,12 @@ namespace MediaBrowser.Server.Implementations.LiveTv const bool isAudio = false; var keys = openToken.Split(new[] { StreamIdDelimeter }, 3); - var mediaSourceId = keys.Length >= 3 ? keys[2] : null; + string mediaSourceId = null; + + if (keys.Length >= 3) + { + mediaSourceId = openToken.Substring(keys[0].Length + keys[1].Length + 2); + } if (string.Equals(keys[0], typeof(LiveTvChannel).Name, StringComparison.OrdinalIgnoreCase)) { diff --git a/MediaBrowser.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunHost.cs b/MediaBrowser.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunHost.cs index 5890e24eb8..4bbbf5a4da 100644 --- a/MediaBrowser.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunHost.cs +++ b/MediaBrowser.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunHost.cs @@ -22,7 +22,8 @@ namespace MediaBrowser.Server.Implementations.LiveTv.TunerHosts.HdHomerun private readonly IHttpClient _httpClient; private readonly IJsonSerializer _jsonSerializer; - public HdHomerunHost(IConfigurationManager config, ILogger logger, IHttpClient httpClient, IJsonSerializer jsonSerializer) : base(config, logger) + public HdHomerunHost(IConfigurationManager config, ILogger logger, IHttpClient httpClient, IJsonSerializer jsonSerializer) + : base(config, logger) { _httpClient = httpClient; _jsonSerializer = jsonSerializer; @@ -166,6 +167,11 @@ namespace MediaBrowser.Server.Implementations.LiveTv.TunerHosts.HdHomerun { var url = info.Url; + if (string.IsNullOrWhiteSpace(url)) + { + throw new ArgumentException("Invalid tuner info"); + } + if (!url.StartsWith("http", StringComparison.OrdinalIgnoreCase)) { url = "http://" + url; @@ -382,7 +388,10 @@ namespace MediaBrowser.Server.Implementations.LiveTv.TunerHosts.HdHomerun public async Task Validate(TunerHostInfo info) { - await GetChannels(info, false, CancellationToken.None).ConfigureAwait(false); + if (info.IsEnabled) + { + await GetChannels(info, false, CancellationToken.None).ConfigureAwait(false); + } } protected override async Task<bool> IsAvailableInternal(TunerHostInfo tuner, string channelId, CancellationToken cancellationToken) diff --git a/SharedVersion.cs b/SharedVersion.cs index 3d8be801e7..2b86442111 100644 --- a/SharedVersion.cs +++ b/SharedVersion.cs @@ -1,4 +1,4 @@ using System.Reflection; -//[assembly: AssemblyVersion("3.0.*")] -[assembly: AssemblyVersion("3.0.5713.0")] +[assembly: AssemblyVersion("3.0.*")] +//[assembly: AssemblyVersion("3.0.5713.0")] -- cgit v1.2.3 From 8046a514187f0ef003c2d828dcf31de6e85ecedb Mon Sep 17 00:00:00 2001 From: Luke Pulverenti <luke.pulverenti@gmail.com> Date: Mon, 24 Aug 2015 23:13:04 -0400 Subject: add more live tv buttons --- MediaBrowser.Api/LiveTv/LiveTvService.cs | 11 +++++- MediaBrowser.Model/LiveTv/LiveTvChannelQuery.cs | 6 ++++ .../LiveTv/LiveTvManager.cs | 40 +++++++--------------- .../LiveTv/TunerHosts/HdHomerun/HdHomerunHost.cs | 4 +-- .../Persistence/SqliteItemRepository.cs | 34 +++++++++++++++++- 5 files changed, 64 insertions(+), 31 deletions(-) (limited to 'MediaBrowser.Model/LiveTv') diff --git a/MediaBrowser.Api/LiveTv/LiveTvService.cs b/MediaBrowser.Api/LiveTv/LiveTvService.cs index d47a7e2d6d..07e64c98d4 100644 --- a/MediaBrowser.Api/LiveTv/LiveTvService.cs +++ b/MediaBrowser.Api/LiveTv/LiveTvService.cs @@ -78,6 +78,14 @@ namespace MediaBrowser.Api.LiveTv /// <value>The fields.</value> [ApiMember(Name = "Fields", Description = "Optional. Specify additional fields of information to return in the output. This allows multiple, comma delimeted. Options: Budget, Chapters, CriticRatingSummary, DateCreated, Genres, HomePageUrl, IndexOptions, MediaStreams, Overview, ParentId, Path, People, ProviderIds, PrimaryImageAspectRatio, Revenue, SortName, Studios, Taglines", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET", AllowMultiple = true)] public string Fields { get; set; } + + [ApiMember(Name = "AddCurrentProgram", Description = "Optional. Adds current program info to each channel", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET")] + public bool AddCurrentProgram { get; set; } + + public GetChannels() + { + AddCurrentProgram = true; + } } [Route("/LiveTv/Channels/{Id}", "GET", Summary = "Gets a live tv channel")] @@ -582,7 +590,8 @@ namespace MediaBrowser.Api.LiveTv IsFavorite = request.IsFavorite, IsLiked = request.IsLiked, IsDisliked = request.IsDisliked, - EnableFavoriteSorting = request.EnableFavoriteSorting + EnableFavoriteSorting = request.EnableFavoriteSorting, + AddCurrentProgram = request.AddCurrentProgram }, GetDtoOptions(request), CancellationToken.None).ConfigureAwait(false); diff --git a/MediaBrowser.Model/LiveTv/LiveTvChannelQuery.cs b/MediaBrowser.Model/LiveTv/LiveTvChannelQuery.cs index 900537b7a2..3a6ad04448 100644 --- a/MediaBrowser.Model/LiveTv/LiveTvChannelQuery.cs +++ b/MediaBrowser.Model/LiveTv/LiveTvChannelQuery.cs @@ -53,5 +53,11 @@ namespace MediaBrowser.Model.LiveTv /// </summary> /// <value>The limit.</value> public int? Limit { get; set; } + + /// <summary> + /// Gets or sets a value indicating whether [add current program]. + /// </summary> + /// <value><c>true</c> if [add current program]; otherwise, <c>false</c>.</value> + public bool AddCurrentProgram { get; set; } } } diff --git a/MediaBrowser.Server.Implementations/LiveTv/LiveTvManager.cs b/MediaBrowser.Server.Implementations/LiveTv/LiveTvManager.cs index 653adb7163..9cd4a2334e 100644 --- a/MediaBrowser.Server.Implementations/LiveTv/LiveTvManager.cs +++ b/MediaBrowser.Server.Implementations/LiveTv/LiveTvManager.cs @@ -251,13 +251,14 @@ namespace MediaBrowser.Server.Implementations.LiveTv var now = DateTime.UtcNow; - var programs = _libraryManager.QueryItems(new InternalItemsQuery + var programs = query.AddCurrentProgram ? _libraryManager.QueryItems(new InternalItemsQuery { IncludeItemTypes = new[] { typeof(LiveTvProgram).Name }, MaxStartDate = now, - MinEndDate = now + MinEndDate = now, + ChannelIds = internalResult.Items.Select(i => i.Id.ToString("N")).ToArray() - }).Items.Cast<LiveTvProgram>().OrderBy(i => i.StartDate).ToList(); + }).Items.Cast<LiveTvProgram>().OrderBy(i => i.StartDate).ToList() : new List<LiveTvProgram>(); foreach (var channel in internalResult.Items) { @@ -776,7 +777,11 @@ namespace MediaBrowser.Server.Implementations.LiveTv IsMovie = query.IsMovie, IsSports = query.IsSports, IsKids = query.IsKids, - Genres = query.Genres + Genres = query.Genres, + StartIndex = query.StartIndex, + Limit = query.Limit, + SortBy = query.SortBy, + SortOrder = query.SortOrder ?? SortOrder.Ascending }; var user = string.IsNullOrEmpty(query.UserId) ? null : _userManager.GetUserById(query.UserId); @@ -802,29 +807,10 @@ namespace MediaBrowser.Server.Implementations.LiveTv } } - IEnumerable<LiveTvProgram> programs = _libraryManager.QueryItems(internalQuery).Items.Cast<LiveTvProgram>(); - - programs = _libraryManager.Sort(programs, user, query.SortBy, query.SortOrder ?? SortOrder.Ascending) - .Cast<LiveTvProgram>(); - - var programList = programs.ToList(); - IEnumerable<LiveTvProgram> returnPrograms = programList; - - if (query.StartIndex.HasValue) - { - returnPrograms = returnPrograms.Skip(query.StartIndex.Value); - } + var queryResult = _libraryManager.QueryItems(internalQuery); - if (query.Limit.HasValue) - { - returnPrograms = returnPrograms.Take(query.Limit.Value); - } - - var returnArray = returnPrograms - .Select(i => - { - return _dtoService.GetBaseItemDto(i, options, user); - }) + var returnArray = queryResult.Items + .Select(i => _dtoService.GetBaseItemDto(i, options, user)) .ToArray(); await AddRecordingInfo(returnArray, cancellationToken).ConfigureAwait(false); @@ -832,7 +818,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv var result = new QueryResult<BaseItemDto> { Items = returnArray, - TotalRecordCount = programList.Count + TotalRecordCount = queryResult.TotalRecordCount }; return result; diff --git a/MediaBrowser.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunHost.cs b/MediaBrowser.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunHost.cs index 4bbbf5a4da..cab21bc3af 100644 --- a/MediaBrowser.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunHost.cs +++ b/MediaBrowser.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunHost.cs @@ -108,7 +108,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv.TunerHosts.HdHomerun public async Task<List<LiveTvTunerInfo>> GetTunerInfos(TunerHostInfo info, CancellationToken cancellationToken) { - string model = await GetModelInfo(info, cancellationToken).ConfigureAwait(false); + var model = await GetModelInfo(info, cancellationToken).ConfigureAwait(false); using (var stream = await _httpClient.Get(new HttpRequestOptions() { @@ -398,7 +398,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv.TunerHosts.HdHomerun { var info = await GetTunerInfos(tuner, cancellationToken).ConfigureAwait(false); - return info.Any(i => i.Status == LiveTvTunerStatus.Available); + return info.Any(i => i.Status == LiveTvTunerStatus.Available || string.Equals(i.ChannelId, channelId, StringComparison.OrdinalIgnoreCase)); } } } diff --git a/MediaBrowser.Server.Implementations/Persistence/SqliteItemRepository.cs b/MediaBrowser.Server.Implementations/Persistence/SqliteItemRepository.cs index 3ec45c4def..f6a04f303d 100644 --- a/MediaBrowser.Server.Implementations/Persistence/SqliteItemRepository.cs +++ b/MediaBrowser.Server.Implementations/Persistence/SqliteItemRepository.cs @@ -712,6 +712,8 @@ namespace MediaBrowser.Server.Implementations.Persistence cmd.CommandText += whereText; + cmd.CommandText += GetOrderByText(query); + if (query.Limit.HasValue) { cmd.CommandText += " LIMIT " + query.Limit.Value.ToString(CultureInfo.InvariantCulture); @@ -719,6 +721,8 @@ namespace MediaBrowser.Server.Implementations.Persistence cmd.CommandText += "; select count (guid) from TypedBaseItems" + whereTextWithoutPaging; + _logger.Debug(cmd.CommandText); + var list = new List<BaseItem>(); var count = 0; @@ -747,6 +751,28 @@ namespace MediaBrowser.Server.Implementations.Persistence } } + private string GetOrderByText(InternalItemsQuery query) + { + if (query.SortBy == null || query.SortBy.Length == 0) + { + return string.Empty; + } + + var sortOrder = query.SortOrder == SortOrder.Descending ? "DESC" : "ASC"; + + return " ORDER BY " + string.Join(",", query.SortBy.Select(i => MapOrderByField(i) + " " + sortOrder).ToArray()); + } + + private string MapOrderByField(string name) + { + if (string.Equals(name, "sortname", StringComparison.OrdinalIgnoreCase)) + { + return "name"; + } + + return name; + } + public List<Guid> GetItemIdsList(InternalItemsQuery query) { if (query == null) @@ -768,6 +794,8 @@ namespace MediaBrowser.Server.Implementations.Persistence cmd.CommandText += whereText; + cmd.CommandText += GetOrderByText(query); + if (query.Limit.HasValue) { cmd.CommandText += " LIMIT " + query.Limit.Value.ToString(CultureInfo.InvariantCulture); @@ -816,6 +844,8 @@ namespace MediaBrowser.Server.Implementations.Persistence cmd.CommandText += whereText; + cmd.CommandText += GetOrderByText(query); + if (query.Limit.HasValue) { cmd.CommandText += " LIMIT " + query.Limit.Value.ToString(CultureInfo.InvariantCulture); @@ -985,7 +1015,9 @@ namespace MediaBrowser.Server.Implementations.Persistence string.Empty : " where " + string.Join(" AND ", whereClauses.ToArray()); - whereClauses.Add(string.Format("Id NOT IN (SELECT Id FROM TypedBaseItems {0} ORDER BY DateCreated DESC LIMIT {1})", + var orderBy = GetOrderByText(query); + + whereClauses.Add(string.Format("guid NOT IN (SELECT guid FROM TypedBaseItems {0}" + orderBy + " LIMIT {1})", pagingWhereText, query.StartIndex.Value.ToString(CultureInfo.InvariantCulture))); } -- cgit v1.2.3