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.Controller/LiveTv/ChannelInfo.cs | 6 ++- .../LiveTv/IListingsProvider.cs | 7 +++ MediaBrowser.Controller/LiveTv/ITunerHost.cs | 50 ++++++++++++++++++++++ 3 files changed, 62 insertions(+), 1 deletion(-) create mode 100644 MediaBrowser.Controller/LiveTv/IListingsProvider.cs create mode 100644 MediaBrowser.Controller/LiveTv/ITunerHost.cs (limited to 'MediaBrowser.Controller/LiveTv') diff --git a/MediaBrowser.Controller/LiveTv/ChannelInfo.cs b/MediaBrowser.Controller/LiveTv/ChannelInfo.cs index cdc9c76c8..32b8abdc5 100644 --- a/MediaBrowser.Controller/LiveTv/ChannelInfo.cs +++ b/MediaBrowser.Controller/LiveTv/ChannelInfo.cs @@ -48,6 +48,10 @@ namespace MediaBrowser.Controller.LiveTv /// /// null if [has image] contains no value, true if [has image]; otherwise, false. public bool? HasImage { get; set; } - + /// + /// Gets or sets a value indicating whether this instance is favorite. + /// + /// null if [is favorite] contains no value, true if [is favorite]; otherwise, false. + public bool? IsFavorite { get; set; } } } diff --git a/MediaBrowser.Controller/LiveTv/IListingsProvider.cs b/MediaBrowser.Controller/LiveTv/IListingsProvider.cs new file mode 100644 index 000000000..2cef455e8 --- /dev/null +++ b/MediaBrowser.Controller/LiveTv/IListingsProvider.cs @@ -0,0 +1,7 @@ + +namespace MediaBrowser.Controller.LiveTv +{ + public interface IListingsProvider + { + } +} diff --git a/MediaBrowser.Controller/LiveTv/ITunerHost.cs b/MediaBrowser.Controller/LiveTv/ITunerHost.cs new file mode 100644 index 000000000..2fa538c60 --- /dev/null +++ b/MediaBrowser.Controller/LiveTv/ITunerHost.cs @@ -0,0 +1,50 @@ +using MediaBrowser.Model.Dto; +using MediaBrowser.Model.LiveTv; +using System.Collections.Generic; +using System.Threading; +using System.Threading.Tasks; + +namespace MediaBrowser.Controller.LiveTv +{ + public interface ITunerHost + { + /// + /// Gets the name. + /// + /// The name. + string Name { get; } + /// + /// Gets the type. + /// + /// The type. + string Type { get; } + /// + /// Gets the tuner hosts. + /// + /// List<TunerHostInfo>. + List GetTunerHosts(); + /// + /// Gets the channels. + /// + /// The information. + /// The cancellation token. + /// Task<IEnumerable<ChannelInfo>>. + Task> GetChannels(TunerHostInfo info, CancellationToken cancellationToken); + /// + /// Gets the tuner infos. + /// + /// The information. + /// The cancellation token. + /// Task<List<LiveTvTunerInfo>>. + Task> GetTunerInfos(TunerHostInfo info, CancellationToken cancellationToken); + /// + /// Gets the channel stream. + /// + /// The information. + /// The channel identifier. + /// The stream identifier. + /// The cancellation token. + /// Task<MediaSourceInfo>. + Task GetChannelStream(TunerHostInfo info, string channelId, string streamId, CancellationToken cancellationToken); + } +} -- 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.Controller/LiveTv') diff --git a/MediaBrowser.Api/LiveTv/LiveTvService.cs b/MediaBrowser.Api/LiveTv/LiveTvService.cs index c474642d5..49ba001ce 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 2cef455e8..75ca7e0dc 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 0cb064aba..4da238acf 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 303b12af7..2ca7397c1 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 264870ffb..25d3b289f 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 d0a271260..b71d62f43 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 000000000..7070c5a5f --- /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 80ec2a036..05bc276b8 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 cadbe7bc3..b5b588682 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 2d56e9656..89ff3a984 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 5a1d9f29e..b6c1321fa 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 bc1d07426..dc149318b 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.Controller/LiveTv') diff --git a/MediaBrowser.Common.Implementations/HttpClientManager/HttpClientManager.cs b/MediaBrowser.Common.Implementations/HttpClientManager/HttpClientManager.cs index 7ca6f43d6..18441161f 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 75ca7e0dc..beaa4eeaf 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 2ca7397c1..c78fbe630 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 18711c61e..337e26e8d 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 0cd4b0a5c..3e58e3bd5 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 315493e0d..77dd54a80 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 b71d62f43..26e070921 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 7070c5a5f..3b7564983 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 89ff3a984..d2b998ae8 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 b6c1321fa..83c2ccf5d 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 ef5bc71ef..1920a9ed7 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.Controller/LiveTv') diff --git a/MediaBrowser.Api/LiveTv/LiveTvService.cs b/MediaBrowser.Api/LiveTv/LiveTvService.cs index 49ba001ce..f40048ce4 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 beaa4eeaf..e509728bf 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 3aa1f66ef..3dbf9a9e9 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 2fa538c60..38ed43bd9 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 c78fbe630..90cd8924d 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 26e070921..6e8213ee0 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 3b7564983..f5b41f3df 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 05bc276b8..a64ce31cf 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 b5b588682..9aacd0c1e 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 615e07a82..e91bd0f0b 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 d2b998ae8..cea0363f4 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 83c2ccf5d..fe099dc67 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 fab6682d7..adef0a45f 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 1920a9ed7..bc2b8eb7a 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 23bab4030872268fdfe98d27f7136d5279d990f8 Mon Sep 17 00:00:00 2001 From: Luke Pulverenti <luke.pulverenti@gmail.com> Date: Thu, 23 Jul 2015 10:58:27 -0400 Subject: update tv guide --- .../LiveTv/IListingsProvider.cs | 2 +- .../LiveTv/EmbyTV/EmbyTV.cs | 11 +----- .../LiveTv/Listings/SchedulesDirect.cs | 39 ++-------------------- .../Localization/Server/server.json | 7 ++-- .../Localization/iso6392.txt | 1 + 5 files changed, 10 insertions(+), 50 deletions(-) (limited to 'MediaBrowser.Controller/LiveTv') diff --git a/MediaBrowser.Controller/LiveTv/IListingsProvider.cs b/MediaBrowser.Controller/LiveTv/IListingsProvider.cs index e509728bf..54977c8d3 100644 --- a/MediaBrowser.Controller/LiveTv/IListingsProvider.cs +++ b/MediaBrowser.Controller/LiveTv/IListingsProvider.cs @@ -11,7 +11,7 @@ namespace MediaBrowser.Controller.LiveTv { string Name { get; } string Type { get; } - Task<IEnumerable<ProgramInfo>> GetProgramsAsync(ListingsProviderInfo info, ChannelInfo channel, DateTime startDateUtc, DateTime endDateUtc, CancellationToken cancellationToken); + Task<IEnumerable<ProgramInfo>> GetProgramsAsync(ListingsProviderInfo info, string channelNumber, 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.Server.Implementations/LiveTv/EmbyTV/EmbyTV.cs b/MediaBrowser.Server.Implementations/LiveTv/EmbyTV/EmbyTV.cs index 6e8213ee0..37b6bf086 100644 --- a/MediaBrowser.Server.Implementations/LiveTv/EmbyTV/EmbyTV.cs +++ b/MediaBrowser.Server.Implementations/LiveTv/EmbyTV/EmbyTV.cs @@ -257,18 +257,9 @@ namespace MediaBrowser.Server.Implementations.LiveTv.EmbyTV public async Task<IEnumerable<ProgramInfo>> GetProgramsAsync(string channelId, DateTime startDateUtc, DateTime endDateUtc, CancellationToken cancellationToken) { - 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<ProgramInfo>(); - } - foreach (var provider in GetListingProviders()) { - var programs = await provider.Item1.GetProgramsAsync(provider.Item2, channelInfo, startDateUtc, endDateUtc, cancellationToken) + var programs = await provider.Item1.GetProgramsAsync(provider.Item2, channelId, startDateUtc, endDateUtc, cancellationToken) .ConfigureAwait(false); var list = programs.ToList(); diff --git a/MediaBrowser.Server.Implementations/LiveTv/Listings/SchedulesDirect.cs b/MediaBrowser.Server.Implementations/LiveTv/Listings/SchedulesDirect.cs index f5b41f3df..2656397bb 100644 --- a/MediaBrowser.Server.Implementations/LiveTv/Listings/SchedulesDirect.cs +++ b/MediaBrowser.Server.Implementations/LiveTv/Listings/SchedulesDirect.cs @@ -35,10 +35,8 @@ namespace MediaBrowser.Server.Implementations.LiveTv.Listings _httpClient = httpClient; } - public async Task<IEnumerable<ProgramInfo>> GetProgramsAsync(ListingsProviderInfo info, ChannelInfo channel, DateTime startDateUtc, DateTime endDateUtc, CancellationToken cancellationToken) + public async Task<IEnumerable<ProgramInfo>> GetProgramsAsync(ListingsProviderInfo info, string channelNumber, DateTime startDateUtc, DateTime endDateUtc, CancellationToken cancellationToken) { - var channelNumber = channel.Number; - List<ProgramInfo> programsInfo = new List<ProgramInfo>(); var token = await GetToken(info, cancellationToken); @@ -74,7 +72,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv.Listings ScheduleDirect.Station station = null; - if (!_channelPair.TryGetValue("", out station)) + if (!_channelPair.TryGetValue(channelNumber, out station)) { return programsInfo; } @@ -217,39 +215,6 @@ namespace MediaBrowser.Server.Implementations.LiveTv.Listings } } - private async Task<ScheduleDirect.Channel> 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<ScheduleDirect.Channel>(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) { diff --git a/MediaBrowser.Server.Implementations/Localization/Server/server.json b/MediaBrowser.Server.Implementations/Localization/Server/server.json index fe099dc67..24df7c983 100644 --- a/MediaBrowser.Server.Implementations/Localization/Server/server.json +++ b/MediaBrowser.Server.Implementations/Localization/Server/server.json @@ -345,7 +345,9 @@ "ButtonSelectDirectory": "Select Directory", "LabelCustomPaths": "Specify custom paths where desired. Leave fields empty to use the defaults.", "LabelCachePath": "Cache path:", - "LabelCachePathHelp": "Specify a custom location for server cache files, such as images.", + "LabelCachePathHelp": "Specify a custom location for server cache files, such as images. Leave blank to use the server default.", + "LabelRecordingPath": "Recording path:", + "LabelRecordingPathHelp": "Specify a custom location to save recordings. Leave blank to use the server default.", "LabelImagesByNamePath": "Images by name path:", "LabelImagesByNamePathHelp": "Specify a custom location for downloaded actor, genre and studio images.", "LabelMetadataPath": "Metadata path:", @@ -1486,5 +1488,6 @@ "LabelZipCode": "Zip Code:", "GuideProviderListingsStep": "Step 2: Select Listings", "GuideProviderLoginStep": "Step 1: Login", - "LabelLineup": "Lineup" + "LabelLineup": "Lineup", + "MessageTunerDeviceNotListed": "Is your tuner device not listed? Try installing an external service plugin for more Live TV options." } diff --git a/MediaBrowser.Server.Implementations/Localization/iso6392.txt b/MediaBrowser.Server.Implementations/Localization/iso6392.txt index e2ba0be42..665a5375e 100644 --- a/MediaBrowser.Server.Implementations/Localization/iso6392.txt +++ b/MediaBrowser.Server.Implementations/Localization/iso6392.txt @@ -346,6 +346,7 @@ pli||pi|Pali|pali pol||pl|Polish|polonais pon|||Pohnpeian|pohnpei por||pt|Portuguese|portugais +pob||pt-br|Portuguese (Brazil)|portugais pra|||Prakrit languages|prâkrit, langues pro|||Provençal, Old (to 1500)|provençal ancien (jusqu'à 1500) pus||ps|Pushto; Pashto|pachto -- cgit v1.2.3 From f7c1a88166e4ba756f05db12db2c61865cfc6712 Mon Sep 17 00:00:00 2001 From: Luke Pulverenti <luke.pulverenti@gmail.com> Date: Thu, 23 Jul 2015 13:58:20 -0400 Subject: update schedules direct --- MediaBrowser.Api/LiveTv/LiveTvService.cs | 5 ++++- MediaBrowser.Controller/LiveTv/IListingsProvider.cs | 2 +- MediaBrowser.Controller/LiveTv/ILiveTvManager.cs | 3 ++- .../LiveTv/Listings/SchedulesDirect.cs | 14 +++++++++----- .../LiveTv/LiveTvManager.cs | 4 ++-- .../LiveTv/RefreshChannelsScheduledTask.cs | 15 ++++++++++++--- .../TunerHosts/HdHomerun/HdHomerunDiscovery.cs | 20 +++++++++++++++----- 7 files changed, 45 insertions(+), 18 deletions(-) (limited to 'MediaBrowser.Controller/LiveTv') diff --git a/MediaBrowser.Api/LiveTv/LiveTvService.cs b/MediaBrowser.Api/LiveTv/LiveTvService.cs index f40048ce4..d05e0951a 100644 --- a/MediaBrowser.Api/LiveTv/LiveTvService.cs +++ b/MediaBrowser.Api/LiveTv/LiveTvService.cs @@ -369,6 +369,9 @@ namespace MediaBrowser.Api.LiveTv [ApiMember(Name = "Location", Description = "Location", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET")] public string Location { get; set; } + + [ApiMember(Name = "Country", Description = "Country", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET")] + public string Country { get; set; } } public class LiveTvService : BaseApiService @@ -436,7 +439,7 @@ namespace MediaBrowser.Api.LiveTv public async Task<object> Get(GetLineups request) { - var info = await _liveTvManager.GetLineups(request.Id, request.Location).ConfigureAwait(false); + var info = await _liveTvManager.GetLineups(request.Id, request.Country, request.Location).ConfigureAwait(false); return ToOptimizedSerializedResultUsingCache(info); } diff --git a/MediaBrowser.Controller/LiveTv/IListingsProvider.cs b/MediaBrowser.Controller/LiveTv/IListingsProvider.cs index 54977c8d3..5e43f1d27 100644 --- a/MediaBrowser.Controller/LiveTv/IListingsProvider.cs +++ b/MediaBrowser.Controller/LiveTv/IListingsProvider.cs @@ -14,6 +14,6 @@ namespace MediaBrowser.Controller.LiveTv Task<IEnumerable<ProgramInfo>> GetProgramsAsync(ListingsProviderInfo info, string channelNumber, 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); + Task<List<NameIdPair>> GetLineups(ListingsProviderInfo info, string country, string location); } } diff --git a/MediaBrowser.Controller/LiveTv/ILiveTvManager.cs b/MediaBrowser.Controller/LiveTv/ILiveTvManager.cs index 3dbf9a9e9..a0deb34f0 100644 --- a/MediaBrowser.Controller/LiveTv/ILiveTvManager.cs +++ b/MediaBrowser.Controller/LiveTv/ILiveTvManager.cs @@ -355,8 +355,9 @@ namespace MediaBrowser.Controller.LiveTv /// Gets the lineups. /// </summary> /// <param name="providerId">The provider identifier.</param> + /// <param name="country">The country.</param> /// <param name="location">The location.</param> /// <returns>Task<List<NameIdPair>>.</returns> - Task<List<NameIdPair>> GetLineups(string providerId, string location); + Task<List<NameIdPair>> GetLineups(string providerId, string country, string location); } } diff --git a/MediaBrowser.Server.Implementations/LiveTv/Listings/SchedulesDirect.cs b/MediaBrowser.Server.Implementations/LiveTv/Listings/SchedulesDirect.cs index 269da5768..ed265d416 100644 --- a/MediaBrowser.Server.Implementations/LiveTv/Listings/SchedulesDirect.cs +++ b/MediaBrowser.Server.Implementations/LiveTv/Listings/SchedulesDirect.cs @@ -387,7 +387,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv.Listings return images; } - public async Task<List<NameIdPair>> GetHeadends(ListingsProviderInfo info, string location, CancellationToken cancellationToken) + public async Task<List<NameIdPair>> GetHeadends(ListingsProviderInfo info, string country, string location, CancellationToken cancellationToken) { var token = await GetToken(info, cancellationToken); @@ -400,9 +400,13 @@ namespace MediaBrowser.Server.Implementations.LiveTv.Listings _logger.Info("Headends on account "); + var countryParam = string.Equals("ca", country, StringComparison.OrdinalIgnoreCase) + ? "Canada" + : "USA"; + var options = new HttpRequestOptions() { - Url = ApiUrl + "/headends?country=USA&postalcode=" + location, + Url = ApiUrl + "/headends?country=" + countryParam + "&postalcode=" + location, UserAgent = UserAgent, CancellationToken = cancellationToken }; @@ -839,12 +843,12 @@ namespace MediaBrowser.Server.Implementations.LiveTv.Listings public async Task Validate(ListingsProviderInfo info) { - await AddLineupToAccount(info, CancellationToken.None).ConfigureAwait(false); + //await AddLineupToAccount(info, CancellationToken.None).ConfigureAwait(false); } - public Task<List<NameIdPair>> GetLineups(ListingsProviderInfo info, string location) + public Task<List<NameIdPair>> GetLineups(ListingsProviderInfo info, string country, string location) { - return GetHeadends(info, location, CancellationToken.None); + return GetHeadends(info, country, location, CancellationToken.None); } } } diff --git a/MediaBrowser.Server.Implementations/LiveTv/LiveTvManager.cs b/MediaBrowser.Server.Implementations/LiveTv/LiveTvManager.cs index 52bb41ba1..5be90e6cc 100644 --- a/MediaBrowser.Server.Implementations/LiveTv/LiveTvManager.cs +++ b/MediaBrowser.Server.Implementations/LiveTv/LiveTvManager.cs @@ -2238,7 +2238,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv return info; } - public Task<List<NameIdPair>> GetLineups(string providerId, string location) + public Task<List<NameIdPair>> GetLineups(string providerId, string country, string location) { var config = GetConfiguration(); @@ -2251,7 +2251,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv throw new ResourceNotFoundException(); } - return provider.GetLineups(info, location); + return provider.GetLineups(info, country, location); } } } diff --git a/MediaBrowser.Server.Implementations/LiveTv/RefreshChannelsScheduledTask.cs b/MediaBrowser.Server.Implementations/LiveTv/RefreshChannelsScheduledTask.cs index de2351434..7cb616d3f 100644 --- a/MediaBrowser.Server.Implementations/LiveTv/RefreshChannelsScheduledTask.cs +++ b/MediaBrowser.Server.Implementations/LiveTv/RefreshChannelsScheduledTask.cs @@ -1,5 +1,7 @@ -using MediaBrowser.Common.ScheduledTasks; +using MediaBrowser.Common.Configuration; +using MediaBrowser.Common.ScheduledTasks; using MediaBrowser.Controller.LiveTv; +using MediaBrowser.Model.LiveTv; using MediaBrowser.Model.Tasks; using System; using System.Collections.Generic; @@ -10,10 +12,12 @@ namespace MediaBrowser.Server.Implementations.LiveTv class RefreshChannelsScheduledTask : IScheduledTask, IConfigurableScheduledTask, IHasKey { private readonly ILiveTvManager _liveTvManager; + private readonly IConfigurationManager _config; - public RefreshChannelsScheduledTask(ILiveTvManager liveTvManager) + public RefreshChannelsScheduledTask(ILiveTvManager liveTvManager, IConfigurationManager config) { _liveTvManager = liveTvManager; + _config = config; } public string Name @@ -50,9 +54,14 @@ namespace MediaBrowser.Server.Implementations.LiveTv }; } + private LiveTvOptions GetConfiguration() + { + return _config.GetConfiguration<LiveTvOptions>("livetv"); + } + public bool IsHidden { - get { return _liveTvManager.Services.Count == 0; } + get { return _liveTvManager.Services.Count == 1 && GetConfiguration().TunerHosts.Count == 0; } } public bool IsEnabled diff --git a/MediaBrowser.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunDiscovery.cs b/MediaBrowser.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunDiscovery.cs index 41652ae9f..4777003d6 100644 --- a/MediaBrowser.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunDiscovery.cs +++ b/MediaBrowser.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunDiscovery.cs @@ -91,15 +91,25 @@ namespace MediaBrowser.Server.Implementations.LiveTv.TunerHosts.HdHomerun private bool UriEquals(string savedUri, string location) { - if (!savedUri.StartsWith("http", StringComparison.OrdinalIgnoreCase)) + return string.Equals(NormalizeUrl(location), NormalizeUrl(savedUri), StringComparison.OrdinalIgnoreCase); + } + + private string NormalizeUrl(string url) + { + if (!url.StartsWith("http", StringComparison.OrdinalIgnoreCase)) { - savedUri = "http://" + savedUri; + url = "http://" + url; } - savedUri = savedUri.TrimEnd('/'); - location = location.TrimEnd('/'); + url = url.TrimEnd('/'); + + // If there isn't a port, add the default port of 80 + if (url.Split(':').Length < 3) + { + url += ":80"; + } - return string.Equals(location, savedUri, StringComparison.OrdinalIgnoreCase); + return url; } private LiveTvOptions GetConfiguration() -- 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.Controller/LiveTv') diff --git a/MediaBrowser.Api/Playback/BaseStreamingService.cs b/MediaBrowser.Api/Playback/BaseStreamingService.cs index e7885a3f8..8505b5d3a 100644 --- a/MediaBrowser.Api/Playback/BaseStreamingService.cs +++ b/MediaBrowser.Api/Playback/BaseStreamingService.cs @@ -924,7 +924,7 @@ namespace MediaBrowser.Api.Playback state.IsoMount = await IsoManager.Mount(state.MediaPath, cancellationTokenSource.Token).ConfigureAwait(false); } - if (state.MediaSource.RequiresOpening) + if (state.MediaSource.RequiresOpening ?? false) { var liveStreamResponse = await MediaSourceManager.OpenLiveStream(new LiveStreamRequest { diff --git a/MediaBrowser.Api/Playback/StreamState.cs b/MediaBrowser.Api/Playback/StreamState.cs index 02b7720a4..4df696096 100644 --- a/MediaBrowser.Api/Playback/StreamState.cs +++ b/MediaBrowser.Api/Playback/StreamState.cs @@ -185,7 +185,7 @@ namespace MediaBrowser.Api.Playback private async void DisposeLiveStream() { - if (MediaSource.RequiresClosing && string.IsNullOrWhiteSpace(Request.LiveStreamId)) + if ((MediaSource.RequiresClosing ?? false) && string.IsNullOrWhiteSpace(Request.LiveStreamId)) { try { diff --git a/MediaBrowser.Controller/LiveTv/ITunerHost.cs b/MediaBrowser.Controller/LiveTv/ITunerHost.cs index 38ed43bd9..c9a96a9ca 100644 --- a/MediaBrowser.Controller/LiveTv/ITunerHost.cs +++ b/MediaBrowser.Controller/LiveTv/ITunerHost.cs @@ -47,6 +47,14 @@ namespace MediaBrowser.Controller.LiveTv /// <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 fbfe79272..9153045e6 100644 --- a/MediaBrowser.MediaEncoding/Encoder/BaseEncoder.cs +++ b/MediaBrowser.MediaEncoding/Encoder/BaseEncoder.cs @@ -436,7 +436,7 @@ namespace MediaBrowser.MediaEncoding.Encoder state.IsoMount = await IsoManager.Mount(state.MediaPath, cancellationToken).ConfigureAwait(false); } - if (state.MediaSource.RequiresOpening) + if (state.MediaSource.RequiresOpening ?? false) { var liveStreamResponse = await MediaSourceManager.OpenLiveStream(new LiveStreamRequest { diff --git a/MediaBrowser.MediaEncoding/Encoder/EncodingJob.cs b/MediaBrowser.MediaEncoding/Encoder/EncodingJob.cs index efce5abb0..bb32ac95b 100644 --- a/MediaBrowser.MediaEncoding/Encoder/EncodingJob.cs +++ b/MediaBrowser.MediaEncoding/Encoder/EncodingJob.cs @@ -137,7 +137,7 @@ namespace MediaBrowser.MediaEncoding.Encoder private async void DisposeLiveStream() { - if (MediaSource.RequiresClosing) + if (MediaSource.RequiresClosing ?? false) { try { diff --git a/MediaBrowser.Model/Dto/MediaSourceInfo.cs b/MediaBrowser.Model/Dto/MediaSourceInfo.cs index 8897edcbd..75edc6a52 100644 --- a/MediaBrowser.Model/Dto/MediaSourceInfo.cs +++ b/MediaBrowser.Model/Dto/MediaSourceInfo.cs @@ -26,9 +26,9 @@ namespace MediaBrowser.Model.Dto public bool SupportsDirectStream { get; set; } public bool SupportsDirectPlay { get; set; } - public bool RequiresOpening { get; set; } + public bool? RequiresOpening { get; set; } public string OpenToken { get; set; } - public bool RequiresClosing { get; set; } + public bool? RequiresClosing { get; set; } public string LiveStreamId { get; set; } public int? BufferMs { get; set; } diff --git a/MediaBrowser.Model/LiveTv/LiveTvOptions.cs b/MediaBrowser.Model/LiveTv/LiveTvOptions.cs index 90cd8924d..3fc841645 100644 --- a/MediaBrowser.Model/LiveTv/LiveTvOptions.cs +++ b/MediaBrowser.Model/LiveTv/LiveTvOptions.cs @@ -34,5 +34,6 @@ namespace MediaBrowser.Model.LiveTv public string Password { get; set; } public string ListingsId { get; set; } public string ZipCode { get; set; } + public string Country { get; set; } } } \ No newline at end of file diff --git a/MediaBrowser.Server.Implementations/Library/MediaSourceManager.cs b/MediaBrowser.Server.Implementations/Library/MediaSourceManager.cs index 9b46a8057..765acd578 100644 --- a/MediaBrowser.Server.Implementations/Library/MediaSourceManager.cs +++ b/MediaBrowser.Server.Implementations/Library/MediaSourceManager.cs @@ -439,7 +439,7 @@ namespace MediaBrowser.Server.Implementations.Library LiveStreamInfo current; if (_openStreams.TryGetValue(id, out current)) { - if (current.MediaSource.RequiresClosing) + if (current.MediaSource.RequiresClosing ?? false) { var tuple = GetProvider(id); diff --git a/MediaBrowser.Server.Implementations/LiveTv/EmbyTV/EmbyTV.cs b/MediaBrowser.Server.Implementations/LiveTv/EmbyTV/EmbyTV.cs index 37b6bf086..c32b8da10 100644 --- a/MediaBrowser.Server.Implementations/LiveTv/EmbyTV/EmbyTV.cs +++ b/MediaBrowser.Server.Implementations/LiveTv/EmbyTV/EmbyTV.cs @@ -1,5 +1,6 @@ using MediaBrowser.Common; using MediaBrowser.Common.Configuration; +using MediaBrowser.Common.Extensions; using MediaBrowser.Common.Net; using MediaBrowser.Controller.Drawing; using MediaBrowser.Controller.LiveTv; @@ -74,20 +75,17 @@ namespace MediaBrowser.Server.Implementations.LiveTv.EmbyTV var status = new LiveTvServiceStatusInfo(); var list = new List<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 e7feeee5a..75dec5f97 100644 --- a/MediaBrowser.Server.Implementations/LiveTv/EmbyTV/ItemDataProvider.cs +++ b/MediaBrowser.Server.Implementations/LiveTv/EmbyTV/ItemDataProvider.cs @@ -68,9 +68,12 @@ namespace MediaBrowser.Server.Implementations.LiveTv.EmbyTV private void UpdateList(List<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 ed265d416..72a965c6a 100644 --- a/MediaBrowser.Server.Implementations/LiveTv/Listings/SchedulesDirect.cs +++ b/MediaBrowser.Server.Implementations/LiveTv/Listings/SchedulesDirect.cs @@ -218,7 +218,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv.Listings private ProgramInfo GetProgram(string channel, ScheduleDirect.Program programInfo, ScheduleDirect.ProgramDetails details) { - _logger.Debug("Show type is: " + (details.showType ?? "No ShowType")); + //_logger.Debug("Show type is: " + (details.showType ?? "No ShowType")); DateTime startAt = DateTime.ParseExact(programInfo.airDateTime, "yyyy'-'MM'-'dd'T'HH':'mm':'ss'Z'", CultureInfo.InvariantCulture); DateTime endAt = startAt.AddSeconds(programInfo.duration); @@ -401,7 +401,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv.Listings _logger.Info("Headends on account "); var countryParam = string.Equals("ca", country, StringComparison.OrdinalIgnoreCase) - ? "Canada" + ? "can" : "USA"; var options = new HttpRequestOptions() @@ -562,6 +562,44 @@ namespace MediaBrowser.Server.Implementations.LiveTv.Listings get { return "SchedulesDirect"; } } + private async Task<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 5be90e6cc..6ef565129 100644 --- a/MediaBrowser.Server.Implementations/LiveTv/LiveTvManager.cs +++ b/MediaBrowser.Server.Implementations/LiveTv/LiveTvManager.cs @@ -367,7 +367,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv info = await service.GetChannelStream(channel.ExternalId, mediaSourceId, cancellationToken).ConfigureAwait(false); info.RequiresClosing = true; - if (info.RequiresClosing) + if (info.RequiresClosing ?? false) { var idPrefix = service.GetType().FullName.GetMD5().ToString("N") + "_"; @@ -384,7 +384,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv info = await service.GetRecordingStream(recording.ExternalId, null, cancellationToken).ConfigureAwait(false); info.RequiresClosing = true; - if (info.RequiresClosing) + if (info.RequiresClosing ?? false) { var idPrefix = service.GetType().FullName.GetMD5().ToString("N") + "_"; diff --git a/MediaBrowser.Server.Implementations/LiveTv/LiveTvMediaSourceProvider.cs b/MediaBrowser.Server.Implementations/LiveTv/LiveTvMediaSourceProvider.cs index 5ebb79629..cf34b6b99 100644 --- a/MediaBrowser.Server.Implementations/LiveTv/LiveTvMediaSourceProvider.cs +++ b/MediaBrowser.Server.Implementations/LiveTv/LiveTvMediaSourceProvider.cs @@ -53,7 +53,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv // Do not use a pipe here because Roku http requests to the server will fail, without any explicit error message. private const char StreamIdDelimeter = '_'; - private const string StreamIdDelimeterString = "|"; + private const string StreamIdDelimeterString = "_"; private async Task<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 4777003d6..cc2bb2d52 100644 --- a/MediaBrowser.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunDiscovery.cs +++ b/MediaBrowser.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunDiscovery.cs @@ -72,6 +72,9 @@ namespace MediaBrowser.Server.Implementations.LiveTv.TunerHosts.HdHomerun return; } + // Strip off the port + url = new Uri(url).GetComponents(UriComponents.AbsoluteUri & ~UriComponents.Port, UriFormat.UriEscaped); + await _liveTvManager.SaveTunerHost(new TunerHostInfo { Type = HdHomerunHost.DeviceType, @@ -103,13 +106,8 @@ namespace MediaBrowser.Server.Implementations.LiveTv.TunerHosts.HdHomerun url = url.TrimEnd('/'); - // If there isn't a port, add the default port of 80 - if (url.Split(':').Length < 3) - { - url += ":80"; - } - - return url; + // Strip off the port + return new Uri(url).GetComponents(UriComponents.AbsoluteUri & ~UriComponents.Port, UriFormat.UriEscaped); } private LiveTvOptions GetConfiguration() diff --git a/MediaBrowser.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunHost.cs b/MediaBrowser.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunHost.cs index 187569ab4..d9f1541c8 100644 --- a/MediaBrowser.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunHost.cs +++ b/MediaBrowser.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunHost.cs @@ -51,7 +51,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv.TunerHosts.HdHomerun { var options = new HttpRequestOptions { - Url = string.Format("{0}/lineup.json", GetApiUrl(info)), + Url = string.Format("{0}/lineup.json", GetApiUrl(info, false)), CancellationToken = cancellationToken }; using (var stream = await _httpClient.Get(options)) @@ -79,7 +79,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv.TunerHosts.HdHomerun using (var stream = await _httpClient.Get(new HttpRequestOptions() { - Url = string.Format("{0}/", GetApiUrl(info)), + Url = string.Format("{0}/", GetApiUrl(info, false)), CancellationToken = cancellationToken })) { @@ -97,7 +97,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv.TunerHosts.HdHomerun using (var stream = await _httpClient.Get(new HttpRequestOptions() { - Url = string.Format("{0}/tuners.html", GetApiUrl(info)), + Url = string.Format("{0}/tuners.html", GetApiUrl(info, false)), CancellationToken = cancellationToken })) { @@ -128,7 +128,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv.TunerHosts.HdHomerun } } - public string GetApiUrl(TunerHostInfo info) + private string GetApiUrl(TunerHostInfo info, bool isPlayback) { var url = info.Url; @@ -137,7 +137,16 @@ namespace MediaBrowser.Server.Implementations.LiveTv.TunerHosts.HdHomerun url = "http://" + url; } - return url.TrimEnd('/'); + var uri = new Uri(url); + + if (isPlayback) + { + var builder = new UriBuilder(uri); + builder.Port = 5004; + uri = builder.Uri; + } + + return uri.AbsoluteUri.TrimEnd('/'); } private static string StripXML(string source) @@ -187,21 +196,13 @@ namespace MediaBrowser.Server.Implementations.LiveTv.TunerHosts.HdHomerun return GetConfiguration().TunerHosts.Where(i => string.Equals(i.Type, Type, StringComparison.OrdinalIgnoreCase)).ToList(); } - public async Task<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 e91bd0f0b..91f25bbee 100644 --- a/MediaBrowser.Server.Implementations/LiveTv/TunerHosts/M3UTunerHost.cs +++ b/MediaBrowser.Server.Implementations/LiveTv/TunerHosts/M3UTunerHost.cs @@ -171,7 +171,9 @@ namespace MediaBrowser.Server.Implementations.LiveTv.TunerHosts Index = -1 } - } + }, + RequiresOpening = false, + RequiresClosing = false }; } throw new ApplicationException("Host doesnt provide this channel"); @@ -193,5 +195,11 @@ namespace MediaBrowser.Server.Implementations.LiveTv.TunerHosts throw new FileNotFoundException(); } } + + + public Task<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 24df7c983..194d406f3 100644 --- a/MediaBrowser.Server.Implementations/Localization/Server/server.json +++ b/MediaBrowser.Server.Implementations/Localization/Server/server.json @@ -1489,5 +1489,5 @@ "GuideProviderListingsStep": "Step 2: Select Listings", "GuideProviderLoginStep": "Step 1: Login", "LabelLineup": "Lineup", - "MessageTunerDeviceNotListed": "Is your tuner device not listed? Try installing an external service plugin for more Live TV options." + "MessageTunerDeviceNotListed": "Is your tuner device not listed? Try installing an external service provider for more Live TV options." } -- cgit v1.2.3 From 14f97d61765c07b406127fec5937aea1e9e81e0f Mon Sep 17 00:00:00 2001 From: Luke Pulverenti <luke.pulverenti@gmail.com> Date: Sat, 25 Jul 2015 13:21:10 -0400 Subject: update schedules direct --- MediaBrowser.Api/LiveTv/LiveTvService.cs | 10 +++--- MediaBrowser.Api/Playback/BaseStreamingService.cs | 12 +++---- MediaBrowser.Api/Playback/Dash/MpegDashService.cs | 4 +-- MediaBrowser.Api/Playback/Hls/DynamicHlsService.cs | 4 +-- MediaBrowser.Api/Playback/Hls/VideoHlsService.cs | 4 +-- .../Playback/Progressive/VideoService.cs | 4 +-- .../LiveTv/IListingsProvider.cs | 2 +- MediaBrowser.Controller/LiveTv/ILiveTvManager.cs | 4 ++- MediaBrowser.Dlna/Didl/DidlBuilder.cs | 40 +++++++++++++++------- .../LiveTv/Listings/SchedulesDirect.cs | 34 +++++++++++------- .../LiveTv/Listings/XmlTv.cs | 2 +- .../LiveTv/LiveTvManager.cs | 4 +-- 12 files changed, 77 insertions(+), 47 deletions(-) (limited to 'MediaBrowser.Controller/LiveTv') diff --git a/MediaBrowser.Api/LiveTv/LiveTvService.cs b/MediaBrowser.Api/LiveTv/LiveTvService.cs index d05e0951a..6c61ef66f 100644 --- a/MediaBrowser.Api/LiveTv/LiveTvService.cs +++ b/MediaBrowser.Api/LiveTv/LiveTvService.cs @@ -1,5 +1,4 @@ -using System.Collections.Generic; -using MediaBrowser.Common.Configuration; +using MediaBrowser.Common.Configuration; using MediaBrowser.Controller.Dto; using MediaBrowser.Controller.Library; using MediaBrowser.Controller.LiveTv; @@ -10,6 +9,7 @@ using MediaBrowser.Model.LiveTv; using MediaBrowser.Model.Querying; using ServiceStack; using System; +using System.Collections.Generic; using System.Globalization; using System.Linq; using System.Threading; @@ -350,6 +350,8 @@ namespace MediaBrowser.Api.LiveTv [Authenticated] public class AddListingProvider : ListingsProviderInfo, IReturn<ListingsProviderInfo> { + public bool ValidateLogin { get; set; } + public bool ValidateListings { get; set; } } [Route("/LiveTv/ListingProviders", "DELETE", Summary = "Deletes a listing provider")] @@ -402,9 +404,9 @@ namespace MediaBrowser.Api.LiveTv } } - public object Post(AddListingProvider request) + public async Task<object> Post(AddListingProvider request) { - var result = _liveTvManager.SaveListingProvider(request).Result; + var result = await _liveTvManager.SaveListingProvider(request, request.ValidateLogin, request.ValidateListings).ConfigureAwait(false); return ToOptimizedResult(result); } diff --git a/MediaBrowser.Api/Playback/BaseStreamingService.cs b/MediaBrowser.Api/Playback/BaseStreamingService.cs index 8505b5d3a..3cc04333a 100644 --- a/MediaBrowser.Api/Playback/BaseStreamingService.cs +++ b/MediaBrowser.Api/Playback/BaseStreamingService.cs @@ -819,11 +819,11 @@ namespace MediaBrowser.Api.Playback /// <summary> /// Gets the audio encoder. /// </summary> - /// <param name="request">The request.</param> + /// <param name="state">The state.</param> /// <returns>System.String.</returns> - protected string GetAudioEncoder(StreamRequest request) + protected string GetAudioEncoder(StreamState state) { - var codec = request.AudioCodec; + var codec = state.OutputAudioCodec; if (string.Equals(codec, "aac", StringComparison.OrdinalIgnoreCase)) { @@ -848,11 +848,11 @@ namespace MediaBrowser.Api.Playback /// <summary> /// Gets the name of the output video codec /// </summary> - /// <param name="request">The request.</param> + /// <param name="state">The state.</param> /// <returns>System.String.</returns> - protected string GetVideoEncoder(VideoStreamRequest request) + protected string GetVideoEncoder(StreamState state) { - var codec = request.VideoCodec; + var codec = state.OutputVideoCodec; if (!string.IsNullOrEmpty(codec)) { diff --git a/MediaBrowser.Api/Playback/Dash/MpegDashService.cs b/MediaBrowser.Api/Playback/Dash/MpegDashService.cs index 47eb38b2d..c201ffd58 100644 --- a/MediaBrowser.Api/Playback/Dash/MpegDashService.cs +++ b/MediaBrowser.Api/Playback/Dash/MpegDashService.cs @@ -378,7 +378,7 @@ namespace MediaBrowser.Api.Playback.Dash protected override string GetAudioArguments(StreamState state) { - var codec = GetAudioEncoder(state.Request); + var codec = GetAudioEncoder(state); if (string.Equals(codec, "copy", StringComparison.OrdinalIgnoreCase)) { @@ -408,7 +408,7 @@ namespace MediaBrowser.Api.Playback.Dash protected override string GetVideoArguments(StreamState state) { - var codec = GetVideoEncoder(state.VideoRequest); + var codec = GetVideoEncoder(state); var args = "-codec:v:0 " + codec; diff --git a/MediaBrowser.Api/Playback/Hls/DynamicHlsService.cs b/MediaBrowser.Api/Playback/Hls/DynamicHlsService.cs index 0a432a580..305547e41 100644 --- a/MediaBrowser.Api/Playback/Hls/DynamicHlsService.cs +++ b/MediaBrowser.Api/Playback/Hls/DynamicHlsService.cs @@ -791,7 +791,7 @@ namespace MediaBrowser.Api.Playback.Hls protected override string GetAudioArguments(StreamState state) { - var codec = GetAudioEncoder(state.Request); + var codec = GetAudioEncoder(state); if (!state.IsOutputVideo) { @@ -856,7 +856,7 @@ namespace MediaBrowser.Api.Playback.Hls return string.Empty; } - var codec = GetVideoEncoder(state.VideoRequest); + var codec = GetVideoEncoder(state); var args = "-codec:v:0 " + codec; diff --git a/MediaBrowser.Api/Playback/Hls/VideoHlsService.cs b/MediaBrowser.Api/Playback/Hls/VideoHlsService.cs index d8e3423fc..dcfafee78 100644 --- a/MediaBrowser.Api/Playback/Hls/VideoHlsService.cs +++ b/MediaBrowser.Api/Playback/Hls/VideoHlsService.cs @@ -48,7 +48,7 @@ namespace MediaBrowser.Api.Playback.Hls /// <returns>System.String.</returns> protected override string GetAudioArguments(StreamState state) { - var codec = GetAudioEncoder(state.Request); + var codec = GetAudioEncoder(state); if (string.Equals(codec, "copy", StringComparison.OrdinalIgnoreCase)) { @@ -83,7 +83,7 @@ namespace MediaBrowser.Api.Playback.Hls /// <returns>System.String.</returns> protected override string GetVideoArguments(StreamState state) { - var codec = GetVideoEncoder(state.VideoRequest); + var codec = GetVideoEncoder(state); var args = "-codec:v:0 " + codec; diff --git a/MediaBrowser.Api/Playback/Progressive/VideoService.cs b/MediaBrowser.Api/Playback/Progressive/VideoService.cs index ebd72b2ce..84ae26248 100644 --- a/MediaBrowser.Api/Playback/Progressive/VideoService.cs +++ b/MediaBrowser.Api/Playback/Progressive/VideoService.cs @@ -89,7 +89,7 @@ namespace MediaBrowser.Api.Playback.Progressive protected override string GetCommandLineArguments(string outputPath, StreamState state, bool isEncoding) { // Get the output codec name - var videoCodec = GetVideoEncoder(state.VideoRequest); + var videoCodec = GetVideoEncoder(state); var format = string.Empty; var keyFrame = string.Empty; @@ -183,7 +183,7 @@ namespace MediaBrowser.Api.Playback.Progressive } // Get the output codec name - var codec = GetAudioEncoder(state.Request); + var codec = GetAudioEncoder(state); var args = "-codec:a:0 " + codec; diff --git a/MediaBrowser.Controller/LiveTv/IListingsProvider.cs b/MediaBrowser.Controller/LiveTv/IListingsProvider.cs index 5e43f1d27..e60183bd9 100644 --- a/MediaBrowser.Controller/LiveTv/IListingsProvider.cs +++ b/MediaBrowser.Controller/LiveTv/IListingsProvider.cs @@ -13,7 +13,7 @@ namespace MediaBrowser.Controller.LiveTv string Type { get; } Task<IEnumerable<ProgramInfo>> GetProgramsAsync(ListingsProviderInfo info, string channelNumber, DateTime startDateUtc, DateTime endDateUtc, CancellationToken cancellationToken); Task AddMetadata(ListingsProviderInfo info, List<ChannelInfo> channels, CancellationToken cancellationToken); - Task Validate(ListingsProviderInfo info); + Task Validate(ListingsProviderInfo info, bool validateLogin, bool validateListings); Task<List<NameIdPair>> GetLineups(ListingsProviderInfo info, string country, string location); } } diff --git a/MediaBrowser.Controller/LiveTv/ILiveTvManager.cs b/MediaBrowser.Controller/LiveTv/ILiveTvManager.cs index a0deb34f0..259f6925b 100644 --- a/MediaBrowser.Controller/LiveTv/ILiveTvManager.cs +++ b/MediaBrowser.Controller/LiveTv/ILiveTvManager.cs @@ -349,8 +349,10 @@ namespace MediaBrowser.Controller.LiveTv /// Saves the listing provider. /// </summary> /// <param name="info">The information.</param> + /// <param name="validateLogin">if set to <c>true</c> [validate login].</param> + /// <param name="validateListings">if set to <c>true</c> [validate listings].</param> /// <returns>Task.</returns> - Task<ListingsProviderInfo> SaveListingProvider(ListingsProviderInfo info); + Task<ListingsProviderInfo> SaveListingProvider(ListingsProviderInfo info, bool validateLogin, bool validateListings); /// <summary> /// Gets the lineups. /// </summary> diff --git a/MediaBrowser.Dlna/Didl/DidlBuilder.cs b/MediaBrowser.Dlna/Didl/DidlBuilder.cs index 50a6f3ba6..0e4cf7392 100644 --- a/MediaBrowser.Dlna/Didl/DidlBuilder.cs +++ b/MediaBrowser.Dlna/Didl/DidlBuilder.cs @@ -120,7 +120,7 @@ namespace MediaBrowser.Dlna.Didl } } - AddCover(item, null, element); + AddCover(item, context, null, element); return element; } @@ -481,7 +481,7 @@ namespace MediaBrowser.Dlna.Didl AddCommonFields(folder, stubType, null, container, filter); - AddCover(folder, stubType, container); + AddCover(folder, context, stubType, container); return container; } @@ -764,7 +764,7 @@ namespace MediaBrowser.Dlna.Didl } } - private void AddCover(BaseItem item, StubType? stubType, XmlElement element) + private void AddCover(BaseItem item, BaseItem context, StubType? stubType, XmlElement element) { if (stubType.HasValue && stubType.Value == StubType.People) { @@ -772,7 +772,26 @@ namespace MediaBrowser.Dlna.Didl return; } - var imageInfo = GetImageInfo(item); + ImageDownloadInfo imageInfo = null; + + if (context is UserView) + { + var episode = item as Episode; + if (episode != null) + { + var parent = (BaseItem)episode.Series ?? episode.Season; + if (parent != null) + { + imageInfo = GetImageInfo(parent); + } + } + } + + // Finally, just use the image from the item + if (imageInfo == null) + { + imageInfo = GetImageInfo(item); + } if (imageInfo == null) { @@ -850,7 +869,7 @@ namespace MediaBrowser.Dlna.Didl private void AddEmbeddedImageAsCover(string name, XmlElement element) { var result = element.OwnerDocument; - + var icon = result.CreateElement("upnp", "albumArtURI", NS_UPNP); var profile = result.CreateAttribute("dlna", "profileID", NS_DLNA); profile.InnerText = _profile.AlbumArtPn; @@ -925,14 +944,11 @@ namespace MediaBrowser.Dlna.Didl } } - if (item is Audio || item is Episode) - { - item = item.Parents.FirstOrDefault(i => i.HasImage(ImageType.Primary)); + item = item.Parents.FirstOrDefault(i => i.HasImage(ImageType.Primary)); - if (item != null) - { - return GetImageInfo(item, ImageType.Primary); - } + if (item != null) + { + return GetImageInfo(item, ImageType.Primary); } return null; diff --git a/MediaBrowser.Server.Implementations/LiveTv/Listings/SchedulesDirect.cs b/MediaBrowser.Server.Implementations/LiveTv/Listings/SchedulesDirect.cs index 65d24ee80..5fd9745a1 100644 --- a/MediaBrowser.Server.Implementations/LiveTv/Listings/SchedulesDirect.cs +++ b/MediaBrowser.Server.Implementations/LiveTv/Listings/SchedulesDirect.cs @@ -400,13 +400,9 @@ namespace MediaBrowser.Server.Implementations.LiveTv.Listings _logger.Info("Headends on account "); - var countryParam = string.Equals("ca", country, StringComparison.OrdinalIgnoreCase) - ? "can" - : "USA"; - var options = new HttpRequestOptions() { - Url = ApiUrl + "/headends?country=" + countryParam + "&postalcode=" + location, + Url = ApiUrl + "/headends?country=" + country + "&postalcode=" + location, UserAgent = UserAgent, CancellationToken = cancellationToken }; @@ -595,18 +591,32 @@ namespace MediaBrowser.Server.Implementations.LiveTv.Listings } } - public async Task Validate(ListingsProviderInfo info) + public async Task Validate(ListingsProviderInfo info, bool validateLogin, bool validateListings) { - if (string.IsNullOrWhiteSpace(info.ListingsId)) + if (validateLogin) { - throw new ArgumentException("Listings Id required"); + if (string.IsNullOrWhiteSpace(info.Username)) + { + throw new ArgumentException("Username is required"); + } + if (string.IsNullOrWhiteSpace(info.Password)) + { + throw new ArgumentException("Password is required"); + } } + if (validateListings) + { + if (string.IsNullOrWhiteSpace(info.ListingsId)) + { + throw new ArgumentException("Listings Id required"); + } - var hasLineup = await HasLineup(info, CancellationToken.None).ConfigureAwait(false); + var hasLineup = await HasLineup(info, CancellationToken.None).ConfigureAwait(false); - if (!hasLineup) - { - await AddLineupToAccount(info, CancellationToken.None).ConfigureAwait(false); + if (!hasLineup) + { + await AddLineupToAccount(info, CancellationToken.None).ConfigureAwait(false); + } } } diff --git a/MediaBrowser.Server.Implementations/LiveTv/Listings/XmlTv.cs b/MediaBrowser.Server.Implementations/LiveTv/Listings/XmlTv.cs index 2e6fc8277..de107ced8 100644 --- a/MediaBrowser.Server.Implementations/LiveTv/Listings/XmlTv.cs +++ b/MediaBrowser.Server.Implementations/LiveTv/Listings/XmlTv.cs @@ -30,7 +30,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv.Listings // Might not be needed } - public Task Validate(ListingsProviderInfo info) + public async Task Validate(ListingsProviderInfo info, bool validateLogin, bool validateListings) { // Check that the path or url is valid. If not, throw a file not found exception } diff --git a/MediaBrowser.Server.Implementations/LiveTv/LiveTvManager.cs b/MediaBrowser.Server.Implementations/LiveTv/LiveTvManager.cs index 3ca60ec51..d539562b8 100644 --- a/MediaBrowser.Server.Implementations/LiveTv/LiveTvManager.cs +++ b/MediaBrowser.Server.Implementations/LiveTv/LiveTvManager.cs @@ -2204,7 +2204,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv _taskManager.CancelIfRunningAndQueue<RefreshChannelsScheduledTask>(); } - public async Task<ListingsProviderInfo> SaveListingProvider(ListingsProviderInfo info) + public async Task<ListingsProviderInfo> SaveListingProvider(ListingsProviderInfo info, bool validateLogin, bool validateListings) { info = (ListingsProviderInfo)_jsonSerializer.DeserializeFromString(_jsonSerializer.SerializeToString(info), typeof(ListingsProviderInfo)); @@ -2215,7 +2215,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv throw new ResourceNotFoundException(); } - await provider.Validate(info).ConfigureAwait(false); + await provider.Validate(info, validateLogin, validateListings).ConfigureAwait(false); var config = GetConfiguration(); -- 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.Controller/LiveTv') diff --git a/MediaBrowser.Api/LiveTv/LiveTvService.cs b/MediaBrowser.Api/LiveTv/LiveTvService.cs index 6c61ef66f..b0359194c 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 259f6925b..53ad6dbdc 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 3fc841645..004ee2ce6 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 d539562b8..b7091ee09 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 cc2bb2d52..10baffea6 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 1e30a4fd8..682abd20f 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 2c2fd76a7..e5a36b12f 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 bc2b8eb7a..982d68461 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.Controller/LiveTv') diff --git a/MediaBrowser.Controller/LiveTv/ITunerHost.cs b/MediaBrowser.Controller/LiveTv/ITunerHost.cs index c9a96a9ca..a6c8021d9 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 004ee2ce6..c5e8f4636 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 8c1fc759f..094c4fda6 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 c32b8da10..d5bfc5449 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 b7091ee09..d8e60be5a 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 7cb616d3f..fa1a8b3e7 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 55d3e6a33..c01eb63ab 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 91f25bbee..bb31390f2 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 acd54cb0f..2e61d181b 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 5e5babbb4..b554e0d1c 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 d95057f13bb6d8bfe04ce20138f8cd2fc66c3519 Mon Sep 17 00:00:00 2001 From: Luke Pulverenti <luke.pulverenti@gmail.com> Date: Tue, 28 Jul 2015 15:42:24 -0400 Subject: rework settings page --- MediaBrowser.Controller/Entities/BaseItem.cs | 5 +++++ MediaBrowser.Controller/Entities/InternalItemsQuery.cs | 4 ++-- MediaBrowser.Controller/LiveTv/LiveTvProgram.cs | 14 ++++++++++++++ .../MediaEncoding/ISubtitleEncoder.cs | 18 ------------------ .../Subtitles/SubtitleEncoder.cs | 17 +++++------------ .../IO/LibraryMonitor.cs | 16 ++++++++++++++-- .../Library/LibraryManager.cs | 15 +++++++++------ .../Localization/Core/core.json | 4 +--- .../MediaBrowser.WebDashboard.csproj | 1 + 9 files changed, 51 insertions(+), 43 deletions(-) (limited to 'MediaBrowser.Controller/LiveTv') diff --git a/MediaBrowser.Controller/Entities/BaseItem.cs b/MediaBrowser.Controller/Entities/BaseItem.cs index 3062c00e7..c4917b0d1 100644 --- a/MediaBrowser.Controller/Entities/BaseItem.cs +++ b/MediaBrowser.Controller/Entities/BaseItem.cs @@ -1124,6 +1124,11 @@ namespace MediaBrowser.Controller.Entities rating = OfficialRatingForComparison; } + if (string.IsNullOrWhiteSpace(rating)) + { + return null; + } + return LocalizationManager.GetRatingLevel(rating); } diff --git a/MediaBrowser.Controller/Entities/InternalItemsQuery.cs b/MediaBrowser.Controller/Entities/InternalItemsQuery.cs index c9603c7e3..227a6bd0e 100644 --- a/MediaBrowser.Controller/Entities/InternalItemsQuery.cs +++ b/MediaBrowser.Controller/Entities/InternalItemsQuery.cs @@ -1,6 +1,6 @@ -using System.Collections.Generic; -using MediaBrowser.Model.Entities; +using MediaBrowser.Model.Entities; using System; +using System.Collections.Generic; namespace MediaBrowser.Controller.Entities { diff --git a/MediaBrowser.Controller/LiveTv/LiveTvProgram.cs b/MediaBrowser.Controller/LiveTv/LiveTvProgram.cs index 8232c5c7a..b54a7aaee 100644 --- a/MediaBrowser.Controller/LiveTv/LiveTvProgram.cs +++ b/MediaBrowser.Controller/LiveTv/LiveTvProgram.cs @@ -227,5 +227,19 @@ namespace MediaBrowser.Controller.LiveTv info.IsMovie = IsMovie; return info; } + + public override bool SupportsPeople + { + get + { + // Optimization + if (IsNews || IsSports) + { + return false; + } + + return base.SupportsPeople; + } + } } } diff --git a/MediaBrowser.Controller/MediaEncoding/ISubtitleEncoder.cs b/MediaBrowser.Controller/MediaEncoding/ISubtitleEncoder.cs index e4a2cd007..826711e51 100644 --- a/MediaBrowser.Controller/MediaEncoding/ISubtitleEncoder.cs +++ b/MediaBrowser.Controller/MediaEncoding/ISubtitleEncoder.cs @@ -7,24 +7,6 @@ namespace MediaBrowser.Controller.MediaEncoding { public interface ISubtitleEncoder { - /// <summary> - /// Converts the subtitles. - /// </summary> - /// <param name="stream">The stream.</param> - /// <param name="inputFormat">The input format.</param> - /// <param name="outputFormat">The output format.</param> - /// <param name="startTimeTicks">The start time ticks.</param> - /// <param name="endTimeTicks">The end time ticks.</param> - /// <param name="cancellationToken">The cancellation token.</param> - /// <returns>Task{Stream}.</returns> - Task<Stream> ConvertSubtitles( - Stream stream, - string inputFormat, - string outputFormat, - long startTimeTicks, - long? endTimeTicks, - CancellationToken cancellationToken); - /// <summary> /// Gets the subtitles. /// </summary> diff --git a/MediaBrowser.MediaEncoding/Subtitles/SubtitleEncoder.cs b/MediaBrowser.MediaEncoding/Subtitles/SubtitleEncoder.cs index 60b70ad08..fe616c63e 100644 --- a/MediaBrowser.MediaEncoding/Subtitles/SubtitleEncoder.cs +++ b/MediaBrowser.MediaEncoding/Subtitles/SubtitleEncoder.cs @@ -53,7 +53,7 @@ namespace MediaBrowser.MediaEncoding.Subtitles } } - public async Task<Stream> ConvertSubtitles(Stream stream, + private async Task<Stream> ConvertSubtitles(Stream stream, string inputFormat, string outputFormat, long startTimeTicks, @@ -64,7 +64,9 @@ namespace MediaBrowser.MediaEncoding.Subtitles try { - var trackInfo = await GetTrackInfo(stream, inputFormat, cancellationToken).ConfigureAwait(false); + var reader = GetReader(inputFormat, true); + + var trackInfo = reader.Parse(stream, cancellationToken); FilterEvents(trackInfo, startTimeTicks, endTimeTicks, false); @@ -190,7 +192,7 @@ namespace MediaBrowser.MediaEncoding.Subtitles { throw new ArgumentNullException("charset"); } - + try { return Encoding.GetEncoding(charset); @@ -257,15 +259,6 @@ namespace MediaBrowser.MediaEncoding.Subtitles return new Tuple<string, MediaProtocol, string, bool>(subtitleStream.Path, protocol, currentFormat, true); } - private async Task<SubtitleTrackInfo> GetTrackInfo(Stream stream, - string inputFormat, - CancellationToken cancellationToken) - { - var reader = GetReader(inputFormat, true); - - return reader.Parse(stream, cancellationToken); - } - private ISubtitleParser GetReader(string format, bool throwIfMissing) { if (string.IsNullOrEmpty(format)) diff --git a/MediaBrowser.Server.Implementations/IO/LibraryMonitor.cs b/MediaBrowser.Server.Implementations/IO/LibraryMonitor.cs index d6a1be962..26ccdfc9a 100644 --- a/MediaBrowser.Server.Implementations/IO/LibraryMonitor.cs +++ b/MediaBrowser.Server.Implementations/IO/LibraryMonitor.cs @@ -1,4 +1,5 @@ -using MediaBrowser.Common.IO; +using System.ComponentModel; +using MediaBrowser.Common.IO; using MediaBrowser.Common.ScheduledTasks; using MediaBrowser.Controller.Configuration; using MediaBrowser.Controller.Entities; @@ -338,7 +339,7 @@ namespace MediaBrowser.Server.Implementations.IO } catch { - + } finally { @@ -370,6 +371,17 @@ namespace MediaBrowser.Server.Implementations.IO Logger.ErrorException("Error in Directory watcher for: " + dw.Path, ex); DisposeWatcher(dw); + + if (ex is Win32Exception) + { + Logger.Info("Disabling realtime monitor to prevent future instability"); + + if (ConfigurationManager.Configuration.EnableLibraryMonitor == AutoOnOff.Auto) + { + ConfigurationManager.Configuration.EnableLibraryMonitor = AutoOnOff.Disabled; + Stop(); + } + } } /// <summary> diff --git a/MediaBrowser.Server.Implementations/Library/LibraryManager.cs b/MediaBrowser.Server.Implementations/Library/LibraryManager.cs index 8d51e3e92..497a198fd 100644 --- a/MediaBrowser.Server.Implementations/Library/LibraryManager.cs +++ b/MediaBrowser.Server.Implementations/Library/LibraryManager.cs @@ -2071,14 +2071,17 @@ namespace MediaBrowser.Server.Implementations.Library public List<PersonInfo> GetPeople(BaseItem item) { - var people = GetPeople(new InternalPeopleQuery + if (item.SupportsPeople) { - ItemId = item.Id - }); + var people = GetPeople(new InternalPeopleQuery + { + ItemId = item.Id + }); - if (people.Count > 0) - { - return people; + if (people.Count > 0) + { + return people; + } } return item.People ?? new List<PersonInfo>(); diff --git a/MediaBrowser.Server.Implementations/Localization/Core/core.json b/MediaBrowser.Server.Implementations/Localization/Core/core.json index 44a10f0a9..4eb66929d 100644 --- a/MediaBrowser.Server.Implementations/Localization/Core/core.json +++ b/MediaBrowser.Server.Implementations/Localization/Core/core.json @@ -173,7 +173,5 @@ "HeaderProducer": "Producers", "HeaderWriter": "Writers", "HeaderParentalRatings": "Parental Ratings", - "HeaderCommunityRatings": "Community ratings", - - + "HeaderCommunityRatings": "Community ratings" } diff --git a/MediaBrowser.WebDashboard/MediaBrowser.WebDashboard.csproj b/MediaBrowser.WebDashboard/MediaBrowser.WebDashboard.csproj index f585a7c26..3e67540d8 100644 --- a/MediaBrowser.WebDashboard/MediaBrowser.WebDashboard.csproj +++ b/MediaBrowser.WebDashboard/MediaBrowser.WebDashboard.csproj @@ -204,6 +204,7 @@ <Content Include="dashboard-ui\mypreferenceshome.html"> <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory> </Content> + <Content Include="dashboard-ui\mypreferencesmenu.html" /> <Content Include="dashboard-ui\scripts\actionsheet.js"> <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory> </Content> -- cgit v1.2.3 From 4d7f98361894e9de90ab964c3496fb7f613c28e2 Mon Sep 17 00:00:00 2001 From: Luke Pulverenti <luke.pulverenti@gmail.com> Date: Tue, 28 Jul 2015 23:42:03 -0400 Subject: update recording scheduler --- MediaBrowser.Controller/LiveTv/RecordingInfo.cs | 6 ++++ .../Channels/ChannelPostScanTask.cs | 2 +- .../Channels/RefreshChannelsScheduledTask.cs | 24 ++++++++----- .../IO/LibraryMonitor.cs | 12 +++---- .../LiveTv/EmbyTV/EmbyTV.cs | 40 +++++++++++++++++----- .../LiveTv/EmbyTV/EntryPoint.cs | 16 +++++++++ .../LiveTv/EmbyTV/RecordingHelper.cs | 9 ++--- .../LiveTv/EmbyTV/TimerManager.cs | 16 ++++++++- .../MediaBrowser.Server.Implementations.csproj | 1 + .../ScheduledTasks/RefreshMediaLibraryTask.cs | 2 +- .../MediaBrowser.WebDashboard.csproj | 6 ---- 11 files changed, 94 insertions(+), 40 deletions(-) create mode 100644 MediaBrowser.Server.Implementations/LiveTv/EmbyTV/EntryPoint.cs (limited to 'MediaBrowser.Controller/LiveTv') diff --git a/MediaBrowser.Controller/LiveTv/RecordingInfo.cs b/MediaBrowser.Controller/LiveTv/RecordingInfo.cs index bf453ccf4..e5817d390 100644 --- a/MediaBrowser.Controller/LiveTv/RecordingInfo.cs +++ b/MediaBrowser.Controller/LiveTv/RecordingInfo.cs @@ -16,6 +16,12 @@ namespace MediaBrowser.Controller.LiveTv /// </summary> /// <value>The series timer identifier.</value> public string SeriesTimerId { get; set; } + + /// <summary> + /// Gets or sets the timer identifier. + /// </summary> + /// <value>The timer identifier.</value> + public string TimerId { get; set; } /// <summary> /// ChannelId of the recording. diff --git a/MediaBrowser.Server.Implementations/Channels/ChannelPostScanTask.cs b/MediaBrowser.Server.Implementations/Channels/ChannelPostScanTask.cs index d266cca6c..baf446942 100644 --- a/MediaBrowser.Server.Implementations/Channels/ChannelPostScanTask.cs +++ b/MediaBrowser.Server.Implementations/Channels/ChannelPostScanTask.cs @@ -12,7 +12,7 @@ using System.Threading.Tasks; namespace MediaBrowser.Server.Implementations.Channels { - public class ChannelPostScanTask : ILibraryPostScanTask + public class ChannelPostScanTask { private readonly IChannelManager _channelManager; private readonly IUserManager _userManager; diff --git a/MediaBrowser.Server.Implementations/Channels/RefreshChannelsScheduledTask.cs b/MediaBrowser.Server.Implementations/Channels/RefreshChannelsScheduledTask.cs index b1491d594..df94580a5 100644 --- a/MediaBrowser.Server.Implementations/Channels/RefreshChannelsScheduledTask.cs +++ b/MediaBrowser.Server.Implementations/Channels/RefreshChannelsScheduledTask.cs @@ -1,6 +1,7 @@ using MediaBrowser.Common.ScheduledTasks; using MediaBrowser.Controller.Channels; -using MediaBrowser.Model.Tasks; +using MediaBrowser.Controller.Library; +using MediaBrowser.Model.Logging; using System; using System.Collections.Generic; using System.Threading.Tasks; @@ -9,11 +10,15 @@ namespace MediaBrowser.Server.Implementations.Channels { class RefreshChannelsScheduledTask : IScheduledTask, IConfigurableScheduledTask { - private readonly IChannelManager _manager; + private readonly IChannelManager _channelManager; + private readonly IUserManager _userManager; + private readonly ILogger _logger; - public RefreshChannelsScheduledTask(IChannelManager manager) + public RefreshChannelsScheduledTask(IChannelManager channelManager, IUserManager userManager, ILogger logger) { - _manager = manager; + _channelManager = channelManager; + _userManager = userManager; + _logger = logger; } public string Name @@ -31,11 +36,14 @@ namespace MediaBrowser.Server.Implementations.Channels get { return "Channels"; } } - public Task Execute(System.Threading.CancellationToken cancellationToken, IProgress<double> progress) + public async Task Execute(System.Threading.CancellationToken cancellationToken, IProgress<double> progress) { - var manager = (ChannelManager)_manager; + var manager = (ChannelManager)_channelManager; - return manager.RefreshChannels(progress, cancellationToken); + await manager.RefreshChannels(new Progress<double>(), cancellationToken).ConfigureAwait(false); + + await new ChannelPostScanTask(_channelManager, _userManager, _logger).Run(progress, cancellationToken) + .ConfigureAwait(false); } public IEnumerable<ITaskTrigger> GetDefaultTriggers() @@ -48,7 +56,7 @@ namespace MediaBrowser.Server.Implementations.Channels public bool IsHidden { - get { return true; } + get { return false; } } public bool IsEnabled diff --git a/MediaBrowser.Server.Implementations/IO/LibraryMonitor.cs b/MediaBrowser.Server.Implementations/IO/LibraryMonitor.cs index 26ccdfc9a..e1c529187 100644 --- a/MediaBrowser.Server.Implementations/IO/LibraryMonitor.cs +++ b/MediaBrowser.Server.Implementations/IO/LibraryMonitor.cs @@ -1,5 +1,4 @@ -using System.ComponentModel; -using MediaBrowser.Common.IO; +using MediaBrowser.Common.IO; using MediaBrowser.Common.ScheduledTasks; using MediaBrowser.Controller.Configuration; using MediaBrowser.Controller.Entities; @@ -372,15 +371,12 @@ namespace MediaBrowser.Server.Implementations.IO DisposeWatcher(dw); - if (ex is Win32Exception) + if (ConfigurationManager.Configuration.EnableLibraryMonitor == AutoOnOff.Auto) { Logger.Info("Disabling realtime monitor to prevent future instability"); - if (ConfigurationManager.Configuration.EnableLibraryMonitor == AutoOnOff.Auto) - { - ConfigurationManager.Configuration.EnableLibraryMonitor = AutoOnOff.Disabled; - Stop(); - } + ConfigurationManager.Configuration.EnableLibraryMonitor = AutoOnOff.Disabled; + Stop(); } } diff --git a/MediaBrowser.Server.Implementations/LiveTv/EmbyTV/EmbyTV.cs b/MediaBrowser.Server.Implementations/LiveTv/EmbyTV/EmbyTV.cs index 0ed87bbff..3374a3cc9 100644 --- a/MediaBrowser.Server.Implementations/LiveTv/EmbyTV/EmbyTV.cs +++ b/MediaBrowser.Server.Implementations/LiveTv/EmbyTV/EmbyTV.cs @@ -33,8 +33,12 @@ namespace MediaBrowser.Server.Implementations.LiveTv.EmbyTV private readonly LiveTvManager _liveTvManager; + public static EmbyTV Current; + public EmbyTV(IApplicationHost appHost, ILogger logger, IJsonSerializer jsonSerializer, IHttpClient httpClient, IConfigurationManager config, ILiveTvManager liveTvManager) { + Current = this; + _appHpst = appHost; _logger = logger; _httpClient = httpClient; @@ -48,6 +52,11 @@ namespace MediaBrowser.Server.Implementations.LiveTv.EmbyTV _timerProvider.TimerFired += _timerProvider_TimerFired; } + public void Start() + { + _timerProvider.RestartTimers(); + } + public event EventHandler DataSourceChanged; public event EventHandler<RecordingStatusChangedEventArgs> RecordingStatusChanged; @@ -147,7 +156,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv.EmbyTV public Task CancelSeriesTimerAsync(string timerId, CancellationToken cancellationToken) { - var remove = _seriesTimerProvider.GetAll().SingleOrDefault(r => r.Id == timerId); + var remove = _seriesTimerProvider.GetAll().FirstOrDefault(r => string.Equals(r.Id, timerId, StringComparison.OrdinalIgnoreCase)); if (remove != null) { _seriesTimerProvider.Delete(remove); @@ -157,7 +166,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv.EmbyTV private void CancelTimerInternal(string timerId) { - var remove = _timerProvider.GetAll().SingleOrDefault(r => r.Id == timerId); + var remove = _timerProvider.GetAll().FirstOrDefault(r => string.Equals(r.Id, timerId, StringComparison.OrdinalIgnoreCase)); if (remove != null) { _timerProvider.Delete(remove); @@ -176,11 +185,24 @@ namespace MediaBrowser.Server.Implementations.LiveTv.EmbyTV return Task.FromResult(true); } - public Task DeleteRecordingAsync(string recordingId, CancellationToken cancellationToken) + public async Task DeleteRecordingAsync(string recordingId, CancellationToken cancellationToken) { var remove = _recordingProvider.GetAll().FirstOrDefault(i => string.Equals(i.Id, recordingId, StringComparison.OrdinalIgnoreCase)); if (remove != null) { + if (!string.IsNullOrWhiteSpace(remove.TimerId)) + { + var enableDelay = _activeRecordings.ContainsKey(remove.TimerId); + + CancelTimerInternal(remove.TimerId); + + 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); + } + } + try { File.Delete(remove.Path); @@ -195,7 +217,6 @@ namespace MediaBrowser.Server.Implementations.LiveTv.EmbyTV } _recordingProvider.Delete(remove); } - return Task.FromResult(true); } public Task CreateTimerAsync(TimerInfo info, CancellationToken cancellationToken) @@ -293,6 +314,8 @@ namespace MediaBrowser.Server.Implementations.LiveTv.EmbyTV if (list.Count > 0) { + SaveEpgDataForChannel(channelId, list); + return list; } } @@ -430,7 +453,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv.EmbyTV } var mediaStreamInfo = await GetChannelStream(timer.ChannelId, null, CancellationToken.None); - var duration = (timer.EndDate - RecordingHelper.GetStartTime(timer)).TotalSeconds + timer.PrePaddingSeconds; + var duration = (timer.EndDate - DateTime.UtcNow).TotalSeconds + timer.PostPaddingSeconds; HttpRequestOptions httpRequestOptions = new HttpRequestOptions() { @@ -451,14 +474,14 @@ namespace MediaBrowser.Server.Implementations.LiveTv.EmbyTV recordPath = Path.Combine(recordPath, RecordingHelper.GetRecordingName(timer, info)); Directory.CreateDirectory(Path.GetDirectoryName(recordPath)); - var recording = _recordingProvider.GetAll().FirstOrDefault(x => string.Equals(x.Id, info.Id, StringComparison.OrdinalIgnoreCase)); + var recording = _recordingProvider.GetAll().FirstOrDefault(x => string.Equals(x.ProgramId, info.Id, StringComparison.OrdinalIgnoreCase)); if (recording == null) { recording = new RecordingInfo() { ChannelId = info.ChannelId, - Id = info.Id, + Id = Guid.NewGuid().ToString("N"), StartDate = info.StartDate, EndDate = info.EndDate, Genres = info.Genres ?? null, @@ -480,7 +503,8 @@ namespace MediaBrowser.Server.Implementations.LiveTv.EmbyTV OriginalAirDate = info.OriginalAirDate, Status = RecordingStatus.Scheduled, Overview = info.Overview, - SeriesTimerId = info.Id.Substring(0, 10) + SeriesTimerId = info.Id.Substring(0, 10), + TimerId = timer.Id }; _recordingProvider.Add(recording); } diff --git a/MediaBrowser.Server.Implementations/LiveTv/EmbyTV/EntryPoint.cs b/MediaBrowser.Server.Implementations/LiveTv/EmbyTV/EntryPoint.cs new file mode 100644 index 000000000..713cb9cd3 --- /dev/null +++ b/MediaBrowser.Server.Implementations/LiveTv/EmbyTV/EntryPoint.cs @@ -0,0 +1,16 @@ +using MediaBrowser.Controller.Plugins; + +namespace MediaBrowser.Server.Implementations.LiveTv.EmbyTV +{ + public class EntryPoint : IServerEntryPoint + { + public void Run() + { + EmbyTV.Current.Start(); + } + + public void Dispose() + { + } + } +} diff --git a/MediaBrowser.Server.Implementations/LiveTv/EmbyTV/RecordingHelper.cs b/MediaBrowser.Server.Implementations/LiveTv/EmbyTV/RecordingHelper.cs index 0aa1cb244..db89680d2 100644 --- a/MediaBrowser.Server.Implementations/LiveTv/EmbyTV/RecordingHelper.cs +++ b/MediaBrowser.Server.Implementations/LiveTv/EmbyTV/RecordingHelper.cs @@ -1,11 +1,10 @@ -using System.Text; -using MediaBrowser.Common.Extensions; +using MediaBrowser.Common.Extensions; using MediaBrowser.Controller.LiveTv; -using MediaBrowser.Model.Extensions; using MediaBrowser.Model.Logging; using System; using System.Collections.Generic; using System.Linq; +using System.Text; namespace MediaBrowser.Server.Implementations.LiveTv.EmbyTV { @@ -49,10 +48,6 @@ namespace MediaBrowser.Server.Implementations.LiveTv.EmbyTV public static DateTime GetStartTime(TimerInfo timer) { - if (timer.StartDate.AddSeconds(-timer.PrePaddingSeconds + 1) < DateTime.UtcNow) - { - return DateTime.UtcNow.AddSeconds(1); - } return timer.StartDate.AddSeconds(-timer.PrePaddingSeconds); } diff --git a/MediaBrowser.Server.Implementations/LiveTv/EmbyTV/TimerManager.cs b/MediaBrowser.Server.Implementations/LiveTv/EmbyTV/TimerManager.cs index 323197aa5..0c8d2ca2b 100644 --- a/MediaBrowser.Server.Implementations/LiveTv/EmbyTV/TimerManager.cs +++ b/MediaBrowser.Server.Implementations/LiveTv/EmbyTV/TimerManager.cs @@ -24,6 +24,11 @@ namespace MediaBrowser.Server.Implementations.LiveTv.EmbyTV public void RestartTimers() { StopTimers(); + + foreach (var item in GetAll().ToList()) + { + AddTimer(item); + } } public void StopTimers() @@ -90,7 +95,16 @@ namespace MediaBrowser.Server.Implementations.LiveTv.EmbyTV private void AddTimer(TimerInfo item) { - var timespan = RecordingHelper.GetStartTime(item) - DateTime.UtcNow; + var startDate = RecordingHelper.GetStartTime(item); + var now = DateTime.UtcNow; + + if (startDate < now) + { + EventHelper.FireEventIfNotNull(TimerFired, this, new GenericEventArgs<TimerInfo> { Argument = item }, Logger); + return; + } + + var timespan = startDate - now; var timer = new Timer(TimerCallback, item.Id, timespan, TimeSpan.Zero); diff --git a/MediaBrowser.Server.Implementations/MediaBrowser.Server.Implementations.csproj b/MediaBrowser.Server.Implementations/MediaBrowser.Server.Implementations.csproj index 5e0f374e0..7eddf5ed1 100644 --- a/MediaBrowser.Server.Implementations/MediaBrowser.Server.Implementations.csproj +++ b/MediaBrowser.Server.Implementations/MediaBrowser.Server.Implementations.csproj @@ -217,6 +217,7 @@ <Compile Include="Library\Validators\YearsPostScanTask.cs" /> <Compile Include="LiveTv\ChannelImageProvider.cs" /> <Compile Include="LiveTv\EmbyTV\EmbyTV.cs" /> + <Compile Include="LiveTv\EmbyTV\EntryPoint.cs" /> <Compile Include="LiveTv\EmbyTV\ItemDataProvider.cs" /> <Compile Include="LiveTv\EmbyTV\RecordingHelper.cs" /> <Compile Include="LiveTv\EmbyTV\SeriesTimerManager.cs" /> diff --git a/MediaBrowser.Server.Implementations/ScheduledTasks/RefreshMediaLibraryTask.cs b/MediaBrowser.Server.Implementations/ScheduledTasks/RefreshMediaLibraryTask.cs index 824d859f3..ed284a90d 100644 --- a/MediaBrowser.Server.Implementations/ScheduledTasks/RefreshMediaLibraryTask.cs +++ b/MediaBrowser.Server.Implementations/ScheduledTasks/RefreshMediaLibraryTask.cs @@ -37,7 +37,7 @@ namespace MediaBrowser.Server.Implementations.ScheduledTasks new StartupTrigger(), - new IntervalTrigger{ Interval = TimeSpan.FromHours(6)} + new IntervalTrigger{ Interval = TimeSpan.FromHours(8)} }; } diff --git a/MediaBrowser.WebDashboard/MediaBrowser.WebDashboard.csproj b/MediaBrowser.WebDashboard/MediaBrowser.WebDashboard.csproj index 16dd97387..a4da8c2b7 100644 --- a/MediaBrowser.WebDashboard/MediaBrowser.WebDashboard.csproj +++ b/MediaBrowser.WebDashboard/MediaBrowser.WebDashboard.csproj @@ -742,9 +742,6 @@ <Content Include="dashboard-ui\livetvnewrecording.html"> <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory> </Content> - <Content Include="dashboard-ui\livetvprogram.html"> - <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory> - </Content> <Content Include="dashboard-ui\livetvrecording.html"> <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory> </Content> @@ -1006,9 +1003,6 @@ <Content Include="dashboard-ui\scripts\livetvnewrecording.js"> <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory> </Content> - <Content Include="dashboard-ui\scripts\livetvprogram.js"> - <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory> - </Content> <Content Include="dashboard-ui\scripts\livetvrecording.js"> <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory> </Content> -- 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.Controller/LiveTv') diff --git a/Emby.Drawing/ImageProcessor.cs b/Emby.Drawing/ImageProcessor.cs index 2ba4f5aab..1e4537bae 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 6814ad751..3ff4c4828 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 53ad6dbdc..889875383 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 0e4cf7392..25514f1dc 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 3c6e43fde..b63d797f4 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 c19ba54bd..3f652ea6f 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 4a8ae2365..09d45066b 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 daa137db6..0cf997602 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 31f1b17dd..2ff9a2813 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 87e71e327..2263b3e1f 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 72fea2c79..9ffd8a500 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 d8954724a..f73e648fa 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 1e9292c4543381338df3d0135f326801f0daf2b4 Mon Sep 17 00:00:00 2001 From: Luke Pulverenti <luke.pulverenti@gmail.com> Date: Mon, 10 Aug 2015 15:09:10 -0400 Subject: update tv --- MediaBrowser.Api/LiveTv/LiveTvService.cs | 5 +++- MediaBrowser.Controller/LiveTv/ILiveTvManager.cs | 3 ++- .../LiveTv/Listings/Emby/EmbyListings.cs | 2 +- .../Listings/Emby/EmbyListingsNorthAmerica.cs | 2 +- .../LiveTv/Listings/Emby/IEmbyListingProvider.cs | 2 +- .../LiveTv/LiveTvManager.cs | 28 ++++++++++++++++------ 6 files changed, 30 insertions(+), 12 deletions(-) (limited to 'MediaBrowser.Controller/LiveTv') diff --git a/MediaBrowser.Api/LiveTv/LiveTvService.cs b/MediaBrowser.Api/LiveTv/LiveTvService.cs index bdec55561..e55103230 100644 --- a/MediaBrowser.Api/LiveTv/LiveTvService.cs +++ b/MediaBrowser.Api/LiveTv/LiveTvService.cs @@ -440,6 +440,9 @@ namespace MediaBrowser.Api.LiveTv [ApiMember(Name = "Id", Description = "Provider id", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET")] public string Id { get; set; } + [ApiMember(Name = "Type", Description = "Provider Type", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET")] + public string Type { get; set; } + [ApiMember(Name = "Location", Description = "Location", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET")] public string Location { get; set; } @@ -535,7 +538,7 @@ namespace MediaBrowser.Api.LiveTv public async Task<object> Get(GetLineups request) { - var info = await _liveTvManager.GetLineups(request.Id, request.Country, request.Location).ConfigureAwait(false); + var info = await _liveTvManager.GetLineups(request.Type, request.Id, request.Country, request.Location).ConfigureAwait(false); return ToOptimizedSerializedResultUsingCache(info); } diff --git a/MediaBrowser.Controller/LiveTv/ILiveTvManager.cs b/MediaBrowser.Controller/LiveTv/ILiveTvManager.cs index 889875383..e568b2eae 100644 --- a/MediaBrowser.Controller/LiveTv/ILiveTvManager.cs +++ b/MediaBrowser.Controller/LiveTv/ILiveTvManager.cs @@ -357,10 +357,11 @@ namespace MediaBrowser.Controller.LiveTv /// <summary> /// Gets the lineups. /// </summary> + /// <param name="providerType">Type of the provider.</param> /// <param name="providerId">The provider identifier.</param> /// <param name="country">The country.</param> /// <param name="location">The location.</param> /// <returns>Task<List<NameIdPair>>.</returns> - Task<List<NameIdPair>> GetLineups(string providerId, string country, string location); + Task<List<NameIdPair>> GetLineups(string providerType, string providerId, string country, string location); } } diff --git a/MediaBrowser.Server.Implementations/LiveTv/Listings/Emby/EmbyListings.cs b/MediaBrowser.Server.Implementations/LiveTv/Listings/Emby/EmbyListings.cs index 5edebb393..e446ff469 100644 --- a/MediaBrowser.Server.Implementations/LiveTv/Listings/Emby/EmbyListings.cs +++ b/MediaBrowser.Server.Implementations/LiveTv/Listings/Emby/EmbyListings.cs @@ -48,7 +48,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv.Listings.Emby public Task<List<NameIdPair>> GetLineups(ListingsProviderInfo info, string country, string location) { - return GetListingsProvider(country).GetLineups(info, country, location); + return GetListingsProvider(country).GetLineups(country, location); } private IEmbyListingProvider GetListingsProvider(string country) diff --git a/MediaBrowser.Server.Implementations/LiveTv/Listings/Emby/EmbyListingsNorthAmerica.cs b/MediaBrowser.Server.Implementations/LiveTv/Listings/Emby/EmbyListingsNorthAmerica.cs index 4713e3074..6fc6975a8 100644 --- a/MediaBrowser.Server.Implementations/LiveTv/Listings/Emby/EmbyListingsNorthAmerica.cs +++ b/MediaBrowser.Server.Implementations/LiveTv/Listings/Emby/EmbyListingsNorthAmerica.cs @@ -43,7 +43,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv.Listings.Emby return Task.FromResult(true); } - public async Task<List<NameIdPair>> GetLineups(ListingsProviderInfo info, string country, string location) + public async Task<List<NameIdPair>> GetLineups(string country, string location) { // location = postal code var path = await GetResponse<String>("https://data.emby.media/service/lineups?postalCode=" + location).ConfigureAwait(false); diff --git a/MediaBrowser.Server.Implementations/LiveTv/Listings/Emby/IEmbyListingProvider.cs b/MediaBrowser.Server.Implementations/LiveTv/Listings/Emby/IEmbyListingProvider.cs index 83477acfc..95c22b986 100644 --- a/MediaBrowser.Server.Implementations/LiveTv/Listings/Emby/IEmbyListingProvider.cs +++ b/MediaBrowser.Server.Implementations/LiveTv/Listings/Emby/IEmbyListingProvider.cs @@ -13,6 +13,6 @@ namespace MediaBrowser.Server.Implementations.LiveTv.Listings.Emby Task<IEnumerable<ProgramInfo>> GetProgramsAsync(ListingsProviderInfo info, string channelNumber, DateTime startDateUtc, DateTime endDateUtc, CancellationToken cancellationToken); Task AddMetadata(ListingsProviderInfo info, List<ChannelInfo> channels, CancellationToken cancellationToken); Task Validate(ListingsProviderInfo info, bool validateLogin, bool validateListings); - Task<List<NameIdPair>> GetLineups(ListingsProviderInfo info, string country, string location); + Task<List<NameIdPair>> GetLineups(string country, string location); } } diff --git a/MediaBrowser.Server.Implementations/LiveTv/LiveTvManager.cs b/MediaBrowser.Server.Implementations/LiveTv/LiveTvManager.cs index aa883ce75..02ca7f0f6 100644 --- a/MediaBrowser.Server.Implementations/LiveTv/LiveTvManager.cs +++ b/MediaBrowser.Server.Implementations/LiveTv/LiveTvManager.cs @@ -2272,20 +2272,34 @@ namespace MediaBrowser.Server.Implementations.LiveTv return info; } - public Task<List<NameIdPair>> GetLineups(string providerId, string country, string location) + public Task<List<NameIdPair>> GetLineups(string providerType, string providerId, string country, string location) { var config = GetConfiguration(); - var info = config.ListingProviders.FirstOrDefault(i => string.Equals(i.Id, providerId, StringComparison.OrdinalIgnoreCase)); + if (string.IsNullOrWhiteSpace(providerId)) + { + var provider = _listingProviders.FirstOrDefault(i => string.Equals(providerType, i.Type, StringComparison.OrdinalIgnoreCase)); - var provider = _listingProviders.FirstOrDefault(i => string.Equals(info.Type, i.Type, StringComparison.OrdinalIgnoreCase)); + if (provider == null) + { + throw new ResourceNotFoundException(); + } - if (provider == null) - { - throw new ResourceNotFoundException(); + return provider.GetLineups(null, country, location); } + else + { + var info = config.ListingProviders.FirstOrDefault(i => string.Equals(i.Id, providerId, StringComparison.OrdinalIgnoreCase)); - return provider.GetLineups(info, country, location); + var provider = _listingProviders.FirstOrDefault(i => string.Equals(info.Type, i.Type, StringComparison.OrdinalIgnoreCase)); + + if (provider == null) + { + throw new ResourceNotFoundException(); + } + + return provider.GetLineups(info, country, location); + } } } } -- cgit v1.2.3 From 881fcf2434bc8833c45f4028e5bfa2ad113a9d18 Mon Sep 17 00:00:00 2001 From: Luke Pulverenti <luke.pulverenti@gmail.com> Date: Tue, 11 Aug 2015 13:47:29 -0400 Subject: update components --- MediaBrowser.Controller/LiveTv/ProgramInfo.cs | 17 ++- MediaBrowser.Controller/LiveTv/RecordingInfo.cs | 6 +- MediaBrowser.Controller/LiveTv/SeriesTimerInfo.cs | 6 + .../LiveTv/EmbyTV/EmbyTV.cs | 21 +++- .../Listings/Emby/EmbyListingsNorthAmerica.cs | 133 ++++++++++++++++++++- .../LiveTv/LiveTvManager.cs | 1 + 6 files changed, 170 insertions(+), 14 deletions(-) (limited to 'MediaBrowser.Controller/LiveTv') diff --git a/MediaBrowser.Controller/LiveTv/ProgramInfo.cs b/MediaBrowser.Controller/LiveTv/ProgramInfo.cs index 36f082b02..3f8fc639f 100644 --- a/MediaBrowser.Controller/LiveTv/ProgramInfo.cs +++ b/MediaBrowser.Controller/LiveTv/ProgramInfo.cs @@ -150,7 +150,22 @@ namespace MediaBrowser.Controller.LiveTv /// </summary> /// <value>The production year.</value> public int? ProductionYear { get; set; } - + /// <summary> + /// Gets or sets the home page URL. + /// </summary> + /// <value>The home page URL.</value> + public string HomePageUrl { get; set; } + /// <summary> + /// Gets or sets the series identifier. + /// </summary> + /// <value>The series identifier.</value> + public string SeriesId { get; set; } + /// <summary> + /// Gets or sets the show identifier. + /// </summary> + /// <value>The show identifier.</value> + public string ShowId { get; set; } + public ProgramInfo() { Genres = new List<string>(); diff --git a/MediaBrowser.Controller/LiveTv/RecordingInfo.cs b/MediaBrowser.Controller/LiveTv/RecordingInfo.cs index e5817d390..42064cf50 100644 --- a/MediaBrowser.Controller/LiveTv/RecordingInfo.cs +++ b/MediaBrowser.Controller/LiveTv/RecordingInfo.cs @@ -185,7 +185,11 @@ namespace MediaBrowser.Controller.LiveTv /// </summary> /// <value><c>null</c> if [has image] contains no value, <c>true</c> if [has image]; otherwise, <c>false</c>.</value> public bool? HasImage { get; set; } - + /// <summary> + /// Gets or sets the show identifier. + /// </summary> + /// <value>The show identifier.</value> + public string ShowId { get; set; } public RecordingInfo() { diff --git a/MediaBrowser.Controller/LiveTv/SeriesTimerInfo.cs b/MediaBrowser.Controller/LiveTv/SeriesTimerInfo.cs index 1be6549ff..2d79473f0 100644 --- a/MediaBrowser.Controller/LiveTv/SeriesTimerInfo.cs +++ b/MediaBrowser.Controller/LiveTv/SeriesTimerInfo.cs @@ -94,6 +94,12 @@ namespace MediaBrowser.Controller.LiveTv /// </summary> /// <value><c>true</c> if this instance is post padding required; otherwise, <c>false</c>.</value> public bool IsPostPaddingRequired { get; set; } + + /// <summary> + /// Gets or sets the series identifier. + /// </summary> + /// <value>The series identifier.</value> + public string SeriesId { get; set; } public SeriesTimerInfo() { diff --git a/MediaBrowser.Server.Implementations/LiveTv/EmbyTV/EmbyTV.cs b/MediaBrowser.Server.Implementations/LiveTv/EmbyTV/EmbyTV.cs index c90b9eacb..cf294997b 100644 --- a/MediaBrowser.Server.Implementations/LiveTv/EmbyTV/EmbyTV.cs +++ b/MediaBrowser.Server.Implementations/LiveTv/EmbyTV/EmbyTV.cs @@ -295,6 +295,13 @@ namespace MediaBrowser.Server.Implementations.LiveTv.EmbyTV RecordAnyTime = false, RecordNewOnly = false }; + + if (program != null) + { + defaults.SeriesId = program.SeriesId; + defaults.ProgramId = program.Id; + } + return Task.FromResult(defaults); } @@ -515,8 +522,9 @@ namespace MediaBrowser.Server.Implementations.LiveTv.EmbyTV OriginalAirDate = info.OriginalAirDate, Status = RecordingStatus.Scheduled, Overview = info.Overview, - SeriesTimerId = info.Id.Substring(0, 10), - TimerId = timer.Id + SeriesTimerId = timer.SeriesTimerId, + TimerId = timer.Id, + ShowId = info.ShowId }; _recordingProvider.Add(recording); } @@ -624,7 +632,9 @@ namespace MediaBrowser.Server.Implementations.LiveTv.EmbyTV { allPrograms = GetProgramsForSeries(seriesTimer, allPrograms); - allPrograms = allPrograms.Where(epg => currentRecordings.All(r => r.ProgramId.Substring(0, 14) != epg.Id.Substring(0, 14))); //filtered recordings already running + var recordingShowIds = currentRecordings.Select(i => i.ShowId).ToList(); + + allPrograms = allPrograms.Where(epg => !recordingShowIds.Contains(epg.ShowId, StringComparer.OrdinalIgnoreCase)); return allPrograms.Select(i => RecordingHelper.CreateTimer(i, seriesTimer)); } @@ -638,7 +648,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv.EmbyTV if (seriesTimer.RecordNewOnly) { - allPrograms = allPrograms.Where(epg => !epg.IsRepeat); //Filtered by New only + allPrograms = allPrograms.Where(epg => !epg.IsRepeat); } if (!seriesTimer.RecordAnyChannel) @@ -648,8 +658,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv.EmbyTV allPrograms = allPrograms.Where(epg => seriesTimer.Days.Contains(epg.StartDate.DayOfWeek)); - // TODO: This assumption will require review once additional listing providers are added - return allPrograms.Where(epg => epg.Id.StartsWith(seriesTimer.ProgramId, StringComparison.OrdinalIgnoreCase)); + return allPrograms.Where(epg => string.Equals(epg.SeriesId, seriesTimer.SeriesId, StringComparison.OrdinalIgnoreCase)); } private string GetChannelEpgCachePath(string channelId) diff --git a/MediaBrowser.Server.Implementations/LiveTv/Listings/Emby/EmbyListingsNorthAmerica.cs b/MediaBrowser.Server.Implementations/LiveTv/Listings/Emby/EmbyListingsNorthAmerica.cs index 641505e38..6c1cc5506 100644 --- a/MediaBrowser.Server.Implementations/LiveTv/Listings/Emby/EmbyListingsNorthAmerica.cs +++ b/MediaBrowser.Server.Implementations/LiveTv/Listings/Emby/EmbyListingsNorthAmerica.cs @@ -26,6 +26,8 @@ namespace MediaBrowser.Server.Implementations.LiveTv.Listings.Emby public async Task<IEnumerable<ProgramInfo>> GetProgramsAsync(ListingsProviderInfo info, string channelNumber, DateTime startDateUtc, DateTime endDateUtc, CancellationToken cancellationToken) { + channelNumber = NormalizeNumber(channelNumber); + var url = "https://data.emby.media/service/listings?id=" + info.ListingsId; // Normalize @@ -36,8 +38,100 @@ namespace MediaBrowser.Server.Implementations.LiveTv.Listings.Emby url += "&end=" + endDateUtc.ToString("s", CultureInfo.InvariantCulture) + "Z"; var response = await GetResponse<ListingInfo[]>(url).ConfigureAwait(false); - - return new List<ProgramInfo>(); + + return response.Where(i => IncludeInResults(i, channelNumber)).Select(GetProgramInfo); + } + + private ProgramInfo GetProgramInfo(ListingInfo info) + { + var showType = info.showType ?? string.Empty; + + var program = new ProgramInfo + { + Id = info.listingID.ToString(CultureInfo.InvariantCulture), + Name = GetStringValue(info.showName), + EpisodeTitle = GetStringValue(info.episodeTitle), + HomePageUrl = GetStringValue(info.webLink), + Overview = info.description, + IsHD = info.hd, + IsLive = info.live, + IsPremiere = info.seasonPremiere || info.seriesPremiere, + IsMovie = showType.IndexOf("Movie", StringComparison.OrdinalIgnoreCase) != -1, + IsKids = showType.IndexOf("Children", StringComparison.OrdinalIgnoreCase) != -1, + IsNews = showType.IndexOf("News", StringComparison.OrdinalIgnoreCase) != -1, + IsSports = showType.IndexOf("Sports", StringComparison.OrdinalIgnoreCase) != -1 + }; + + if (!string.IsNullOrWhiteSpace(info.listDateTime)) + { + program.StartDate = DateTime.ParseExact(info.listDateTime, "yyyy'-'MM'-'dd' 'HH':'mm':'ss", CultureInfo.InvariantCulture); + program.EndDate = program.StartDate.AddMinutes(info.duration); + } + + if (info.starRating > 0) + { + program.CommunityRating = info.starRating*2; + } + + if (!string.IsNullOrWhiteSpace(info.rating)) + { + // They don't have dashes so try to normalize + program.OfficialRating = info.rating.Replace("TV", "TV-").Replace("--", "-"); + } + + if (!string.IsNullOrWhiteSpace(info.year)) + { + program.ProductionYear = int.Parse(info.year, CultureInfo.InvariantCulture); + } + + if (info.showID > 0) + { + program.ShowId = info.showID.ToString(CultureInfo.InvariantCulture); + } + + if (info.seriesID > 0) + { + program.SeriesId = info.seriesID.ToString(CultureInfo.InvariantCulture); + program.IsSeries = true; + program.IsRepeat = info.repeat; + } + + if (info.starRating > 0) + { + program.CommunityRating = info.starRating * 2; + } + + if (string.Equals(info.showName, "Movie", StringComparison.OrdinalIgnoreCase)) + { + // Sometimes the movie title will be in here + if (!string.IsNullOrWhiteSpace(info.episodeTitle)) + { + program.Name = info.episodeTitle; + } + } + + return program; + } + + private string GetStringValue(string s) + { + return string.IsNullOrWhiteSpace(s) ? null : s; + } + + private bool IncludeInResults(ListingInfo info, string itemNumber) + { + if (string.Equals(itemNumber, NormalizeNumber(info.number), StringComparison.OrdinalIgnoreCase)) + { + return true; + } + + var channelNumber = info.channelNumber.ToString(CultureInfo.InvariantCulture); + if (info.subChannelNumber > 0) + { + channelNumber += "." + info.subChannelNumber.ToString(CultureInfo.InvariantCulture); + } + + return string.Equals(channelNumber, itemNumber, StringComparison.OrdinalIgnoreCase); } public async Task AddMetadata(ListingsProviderInfo info, List<ChannelInfo> channels, CancellationToken cancellationToken) @@ -48,18 +142,25 @@ namespace MediaBrowser.Server.Implementations.LiveTv.Listings.Emby { var station = response.stations.FirstOrDefault(i => { + var itemNumber = NormalizeNumber(channel.Number); + + if (string.Equals(itemNumber, NormalizeNumber(i.number), StringComparison.OrdinalIgnoreCase)) + { + return true; + } + var channelNumber = i.channelNumber.ToString(CultureInfo.InvariantCulture); if (i.subChannelNumber > 0) { channelNumber += "." + i.subChannelNumber.ToString(CultureInfo.InvariantCulture); } - return string.Equals(channelNumber, channel.Number, StringComparison.OrdinalIgnoreCase); + return string.Equals(channelNumber, itemNumber, StringComparison.OrdinalIgnoreCase); }); if (station != null) { - channel.Name = station.name; + //channel.Name = station.name; if (!string.IsNullOrWhiteSpace(station.logoFilename)) { @@ -70,6 +171,11 @@ namespace MediaBrowser.Server.Implementations.LiveTv.Listings.Emby } } + private string NormalizeNumber(string number) + { + return number.Replace('-', '.'); + } + public Task Validate(ListingsProviderInfo info, bool validateLogin, bool validateListings) { return Task.FromResult(true); @@ -108,7 +214,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv.Listings.Emby return name; } - private async Task<T> GetResponse<T>(string url) + private async Task<T> GetResponse<T>(string url, Func<string, string> filter = null) where T : class { using (var stream = await _httpClient.Get(new HttpRequestOptions @@ -131,12 +237,27 @@ namespace MediaBrowser.Server.Implementations.LiveTv.Listings.Emby }).ConfigureAwait(false)) { - return _jsonSerializer.DeserializeFromStream<T>(secondStream); + return ParseResponse<T>(secondStream, filter); } } } } + private T ParseResponse<T>(Stream response, Func<string,string> filter) + { + using (var reader = new StreamReader(response)) + { + var json = reader.ReadToEnd(); + + if (filter != null) + { + json = filter(json); + } + + return _jsonSerializer.DeserializeFromString<T>(json); + } + } + private class LineupInfo { public string lineupID { get; set; } diff --git a/MediaBrowser.Server.Implementations/LiveTv/LiveTvManager.cs b/MediaBrowser.Server.Implementations/LiveTv/LiveTvManager.cs index 02ca7f0f6..331f42185 100644 --- a/MediaBrowser.Server.Implementations/LiveTv/LiveTvManager.cs +++ b/MediaBrowser.Server.Implementations/LiveTv/LiveTvManager.cs @@ -622,6 +622,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv item.ProviderImageUrl = info.ImageUrl; item.RunTimeTicks = (info.EndDate - info.StartDate).Ticks; item.StartDate = info.StartDate; + item.HomePageUrl = info.HomePageUrl; item.ProductionYear = info.ProductionYear; item.PremiereDate = item.PremiereDate ?? info.OriginalAirDate; -- cgit v1.2.3 From 9c879eefc33df13b7dac555e159d5c4ccf09213e Mon Sep 17 00:00:00 2001 From: Luke Pulverenti <luke.pulverenti@gmail.com> Date: Fri, 14 Aug 2015 15:14:54 -0400 Subject: update channel settings --- MediaBrowser.Controller/LiveTv/ILiveTvManager.cs | 3 +-- MediaBrowser.Model/Configuration/UserConfiguration.cs | 1 + MediaBrowser.Server.Implementations/Library/LibraryManager.cs | 2 +- MediaBrowser.Server.Implementations/Library/UserViewManager.cs | 5 ++--- MediaBrowser.Server.Implementations/LiveTv/LiveTvManager.cs | 6 +++--- 5 files changed, 8 insertions(+), 9 deletions(-) (limited to 'MediaBrowser.Controller/LiveTv') diff --git a/MediaBrowser.Controller/LiveTv/ILiveTvManager.cs b/MediaBrowser.Controller/LiveTv/ILiveTvManager.cs index e568b2eae..df09d39b2 100644 --- a/MediaBrowser.Controller/LiveTv/ILiveTvManager.cs +++ b/MediaBrowser.Controller/LiveTv/ILiveTvManager.cs @@ -273,10 +273,9 @@ namespace MediaBrowser.Controller.LiveTv /// <summary> /// Gets the live tv folder. /// </summary> - /// <param name="userId">The user identifier.</param> /// <param name="cancellationToken">The cancellation token.</param> /// <returns>BaseItemDto.</returns> - Task<Folder> GetInternalLiveTvFolder(string userId, CancellationToken cancellationToken); + Task<Folder> GetInternalLiveTvFolder(CancellationToken cancellationToken); /// <summary> /// Gets the live tv folder. diff --git a/MediaBrowser.Model/Configuration/UserConfiguration.cs b/MediaBrowser.Model/Configuration/UserConfiguration.cs index 9dd84bc7d..349780958 100644 --- a/MediaBrowser.Model/Configuration/UserConfiguration.cs +++ b/MediaBrowser.Model/Configuration/UserConfiguration.cs @@ -50,6 +50,7 @@ namespace MediaBrowser.Model.Configuration public string[] PlainFolderViews { get; set; } public bool HidePlayedInLatest { get; set; } + public bool DisplayChannelsInline { get; set; } /// <summary> /// Initializes a new instance of the <see cref="UserConfiguration" /> class. diff --git a/MediaBrowser.Server.Implementations/Library/LibraryManager.cs b/MediaBrowser.Server.Implementations/Library/LibraryManager.cs index c316aab25..0cfd38479 100644 --- a/MediaBrowser.Server.Implementations/Library/LibraryManager.cs +++ b/MediaBrowser.Server.Implementations/Library/LibraryManager.cs @@ -1824,7 +1824,7 @@ namespace MediaBrowser.Server.Implementations.Library throw new ArgumentNullException("name"); } - var idValues = "37_namedview_" + name + (parentId ?? string.Empty); + var idValues = "37_namedview_" + name + (parentId ?? string.Empty) + (viewType ?? string.Empty); if (!string.IsNullOrWhiteSpace(uniqueId)) { idValues += uniqueId; diff --git a/MediaBrowser.Server.Implementations/Library/UserViewManager.cs b/MediaBrowser.Server.Implementations/Library/UserViewManager.cs index 5d753826a..a609c53ab 100644 --- a/MediaBrowser.Server.Implementations/Library/UserViewManager.cs +++ b/MediaBrowser.Server.Implementations/Library/UserViewManager.cs @@ -156,7 +156,7 @@ namespace MediaBrowser.Server.Implementations.Library var channels = channelResult.Items; var embeddedChannels = channels - .Where(i => user.Configuration.DisplayChannelsWithinViews.Contains(i.Id.ToString("N"))) + .Where(i => user.Configuration.DisplayChannelsInline || user.Configuration.DisplayChannelsWithinViews.Contains(i.Id.ToString("N"))) .ToList(); list.AddRange(embeddedChannels); @@ -168,8 +168,7 @@ namespace MediaBrowser.Server.Implementations.Library if (_liveTvManager.GetEnabledUsers().Select(i => i.Id.ToString("N")).Contains(query.UserId)) { - var name = _localizationManager.GetLocalizedString("ViewType" + CollectionType.LiveTv); - list.Add(await _libraryManager.GetNamedView(name, CollectionType.LiveTv, string.Empty, cancellationToken).ConfigureAwait(false)); + list.Add(await _liveTvManager.GetInternalLiveTvFolder(CancellationToken.None).ConfigureAwait(false)); } } diff --git a/MediaBrowser.Server.Implementations/LiveTv/LiveTvManager.cs b/MediaBrowser.Server.Implementations/LiveTv/LiveTvManager.cs index cc3c06dd4..782473bea 100644 --- a/MediaBrowser.Server.Implementations/LiveTv/LiveTvManager.cs +++ b/MediaBrowser.Server.Implementations/LiveTv/LiveTvManager.cs @@ -2196,15 +2196,15 @@ namespace MediaBrowser.Server.Implementations.LiveTv { var user = string.IsNullOrEmpty(userId) ? null : _userManager.GetUserById(userId); - var folder = await GetInternalLiveTvFolder(userId, cancellationToken).ConfigureAwait(false); + var folder = await GetInternalLiveTvFolder(cancellationToken).ConfigureAwait(false); return _dtoService.GetBaseItemDto(folder, new DtoOptions(), user); } - public async Task<Folder> GetInternalLiveTvFolder(string userId, CancellationToken cancellationToken) + public async Task<Folder> GetInternalLiveTvFolder(CancellationToken cancellationToken) { var name = _localization.GetLocalizedString("ViewTypeLiveTV"); - return await _libraryManager.GetNamedView(name, "livetv", "zz_" + name, cancellationToken).ConfigureAwait(false); + return await _libraryManager.GetNamedView(name, "livetv", name, cancellationToken).ConfigureAwait(false); } public async Task<TunerHostInfo> SaveTunerHost(TunerHostInfo info) -- 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.Controller/LiveTv') diff --git a/MediaBrowser.Controller/LiveTv/LiveTvProgram.cs b/MediaBrowser.Controller/LiveTv/LiveTvProgram.cs index b54a7aaee..0a1735c23 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 7c590307f..70c6892ef 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 9ff8f7206..177a64ddc 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 9ffd8a500..2587b1005 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 782473bea..9065a8ac2 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 b09f8cfef..35f77abcb 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.Controller/LiveTv') diff --git a/MediaBrowser.Controller/LiveTv/LiveTvProgram.cs b/MediaBrowser.Controller/LiveTv/LiveTvProgram.cs index 0a1735c23..b54a7aaee 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 70c6892ef..4b88e42f3 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 177a64ddc..7273ac88e 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 2587b1005..9ffd8a500 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 9065a8ac2..782473bea 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 2f2ccfe8f3217c64a33c1e81c4516358f95c363a Mon Sep 17 00:00:00 2001 From: Luke Pulverenti <luke.pulverenti@gmail.com> Date: Tue, 18 Aug 2015 11:25:57 -0400 Subject: update recordings --- MediaBrowser.Controller/LiveTv/ILiveTvRecording.cs | 3 +++ MediaBrowser.Controller/LiveTv/RecordingInfo.cs | 6 ++++++ .../LiveTv/EmbyTV/EmbyTV.cs | 4 +++- .../LiveTv/LiveTvManager.cs | 14 +++++++++++--- MediaBrowser.Server.Startup.Common/ApplicationHost.cs | 2 +- 5 files changed, 24 insertions(+), 5 deletions(-) (limited to 'MediaBrowser.Controller/LiveTv') diff --git a/MediaBrowser.Controller/LiveTv/ILiveTvRecording.cs b/MediaBrowser.Controller/LiveTv/ILiveTvRecording.cs index 1dd267c93..9fc60beb9 100644 --- a/MediaBrowser.Controller/LiveTv/ILiveTvRecording.cs +++ b/MediaBrowser.Controller/LiveTv/ILiveTvRecording.cs @@ -42,5 +42,8 @@ namespace MediaBrowser.Controller.LiveTv RecordingStatus Status { get; set; } DateTime? EndDate { get; set; } ChannelType ChannelType { get; set; } + DateTime DateLastSaved { get; set; } + DateTime DateCreated { get; set; } + DateTime DateModified { get; set; } } } diff --git a/MediaBrowser.Controller/LiveTv/RecordingInfo.cs b/MediaBrowser.Controller/LiveTv/RecordingInfo.cs index 42064cf50..3006b9bbe 100644 --- a/MediaBrowser.Controller/LiveTv/RecordingInfo.cs +++ b/MediaBrowser.Controller/LiveTv/RecordingInfo.cs @@ -191,6 +191,12 @@ namespace MediaBrowser.Controller.LiveTv /// <value>The show identifier.</value> public string ShowId { get; set; } + /// <summary> + /// Gets or sets the date last updated. + /// </summary> + /// <value>The date last updated.</value> + public DateTime DateLastUpdated { get; set; } + public RecordingInfo() { Genres = new List<string>(); diff --git a/MediaBrowser.Server.Implementations/LiveTv/EmbyTV/EmbyTV.cs b/MediaBrowser.Server.Implementations/LiveTv/EmbyTV/EmbyTV.cs index a28e3faec..51476e296 100644 --- a/MediaBrowser.Server.Implementations/LiveTv/EmbyTV/EmbyTV.cs +++ b/MediaBrowser.Server.Implementations/LiveTv/EmbyTV/EmbyTV.cs @@ -576,6 +576,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv.EmbyTV recording.Path = recordPath; recording.Status = RecordingStatus.InProgress; + recording.DateLastUpdated = DateTime.UtcNow; _recordingProvider.Update(recording); try @@ -598,7 +599,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv.EmbyTV } catch (OperationCanceledException) { - _logger.Info("Recording cancelled"); + _logger.Info("Recording stopped"); recording.Status = RecordingStatus.Completed; } catch (Exception ex) @@ -607,6 +608,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv.EmbyTV recording.Status = RecordingStatus.Error; } + recording.DateLastUpdated = DateTime.UtcNow; _recordingProvider.Update(recording); _timerProvider.Delete(timer); _logger.Info("Recording was a success"); diff --git a/MediaBrowser.Server.Implementations/LiveTv/LiveTvManager.cs b/MediaBrowser.Server.Implementations/LiveTv/LiveTvManager.cs index 1280c52b1..4c44f5c3b 100644 --- a/MediaBrowser.Server.Implementations/LiveTv/LiveTvManager.cs +++ b/MediaBrowser.Server.Implementations/LiveTv/LiveTvManager.cs @@ -1,6 +1,8 @@ -using MediaBrowser.Common; +using System.IO; +using MediaBrowser.Common; using MediaBrowser.Common.Configuration; using MediaBrowser.Common.Extensions; +using MediaBrowser.Common.IO; using MediaBrowser.Common.Progress; using MediaBrowser.Common.ScheduledTasks; using MediaBrowser.Controller.Configuration; @@ -61,8 +63,9 @@ namespace MediaBrowser.Server.Implementations.LiveTv private readonly List<ITunerHost> _tunerHosts = new List<ITunerHost>(); private readonly List<IListingsProvider> _listingProviders = new List<IListingsProvider>(); + private readonly IFileSystem _fileSystem; - 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) + 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, IFileSystem fileSystem) { _config = config; _logger = logger; @@ -73,6 +76,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv _localization = localization; _jsonSerializer = jsonSerializer; _providerManager = providerManager; + _fileSystem = fileSystem; _dtoService = dtoService; _userDataManager = userDataManager; @@ -729,6 +733,10 @@ namespace MediaBrowser.Server.Implementations.LiveTv if (!string.IsNullOrEmpty(info.Path)) { item.Path = info.Path; + var fileInfo = new FileInfo(info.Path); + + recording.DateCreated = _fileSystem.GetCreationTimeUtc(fileInfo); + recording.DateModified = _fileSystem.GetLastWriteTimeUtc(fileInfo); } else if (!string.IsNullOrEmpty(info.Url)) { @@ -741,7 +749,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv { await _libraryManager.CreateItem(item, cancellationToken).ConfigureAwait(false); } - else if (pathChanged) + else if (pathChanged || info.DateLastUpdated > recording.DateLastSaved) { await _libraryManager.UpdateItem(item, ItemUpdateType.MetadataImport, cancellationToken).ConfigureAwait(false); } diff --git a/MediaBrowser.Server.Startup.Common/ApplicationHost.cs b/MediaBrowser.Server.Startup.Common/ApplicationHost.cs index 60ff36c6d..9ecd0764a 100644 --- a/MediaBrowser.Server.Startup.Common/ApplicationHost.cs +++ b/MediaBrowser.Server.Startup.Common/ApplicationHost.cs @@ -496,7 +496,7 @@ namespace MediaBrowser.Server.Startup.Common PlaylistManager = new PlaylistManager(LibraryManager, FileSystemManager, LibraryMonitor, LogManager.GetLogger("PlaylistManager"), UserManager, ProviderManager); RegisterSingleInstance<IPlaylistManager>(PlaylistManager); - LiveTvManager = new LiveTvManager(this, ServerConfigurationManager, Logger, ItemRepository, ImageProcessor, UserDataManager, DtoService, UserManager, LibraryManager, TaskManager, LocalizationManager, JsonSerializer, ProviderManager); + LiveTvManager = new LiveTvManager(this, ServerConfigurationManager, Logger, ItemRepository, ImageProcessor, UserDataManager, DtoService, UserManager, LibraryManager, TaskManager, LocalizationManager, JsonSerializer, ProviderManager, FileSystemManager); RegisterSingleInstance(LiveTvManager); UserViewManager = new UserViewManager(LibraryManager, LocalizationManager, UserManager, ChannelManager, LiveTvManager, PlaylistManager, CollectionManager, ServerConfigurationManager); -- cgit v1.2.3 From 615d1e2a53c9079e6b13789cbaa0410d9039f435 Mon Sep 17 00:00:00 2001 From: Luke Pulverenti <luke.pulverenti@gmail.com> Date: Wed, 19 Aug 2015 02:12:58 -0400 Subject: update detail page --- MediaBrowser.Controller/LiveTv/ProgramInfo.cs | 17 ++++- MediaBrowser.Dlna/Didl/DidlBuilder.cs | 13 ++++ .../LiveTv/Listings/SchedulesDirect.cs | 84 +++++++++++----------- .../LiveTv/LiveTvManager.cs | 26 ++----- 4 files changed, 75 insertions(+), 65 deletions(-) (limited to 'MediaBrowser.Controller/LiveTv') diff --git a/MediaBrowser.Controller/LiveTv/ProgramInfo.cs b/MediaBrowser.Controller/LiveTv/ProgramInfo.cs index 3f8fc639f..467264e7a 100644 --- a/MediaBrowser.Controller/LiveTv/ProgramInfo.cs +++ b/MediaBrowser.Controller/LiveTv/ProgramInfo.cs @@ -33,6 +33,11 @@ namespace MediaBrowser.Controller.LiveTv /// </summary> /// <value>The overview.</value> public string Overview { get; set; } + /// <summary> + /// Gets or sets the short overview. + /// </summary> + /// <value>The short overview.</value> + public string ShortOverview { get; set; } /// <summary> /// The start date of the program, in UTC. @@ -165,7 +170,17 @@ namespace MediaBrowser.Controller.LiveTv /// </summary> /// <value>The show identifier.</value> public string ShowId { get; set; } - + /// <summary> + /// Gets or sets the season number. + /// </summary> + /// <value>The season number.</value> + public int? SeasonNumber { get; set; } + /// <summary> + /// Gets or sets the episode number. + /// </summary> + /// <value>The episode number.</value> + public int? EpisodeNumber { get; set; } + public ProgramInfo() { Genres = new List<string>(); diff --git a/MediaBrowser.Dlna/Didl/DidlBuilder.cs b/MediaBrowser.Dlna/Didl/DidlBuilder.cs index 25514f1dc..390f44267 100644 --- a/MediaBrowser.Dlna/Didl/DidlBuilder.cs +++ b/MediaBrowser.Dlna/Didl/DidlBuilder.cs @@ -193,6 +193,9 @@ namespace MediaBrowser.Dlna.Didl if (string.Equals(subtitleMode, "CaptionInfoEx", StringComparison.OrdinalIgnoreCase)) { + // <sec:CaptionInfoEx sec:type="srt">http://192.168.1.3:9999/video.srt</sec:CaptionInfoEx> + // <sec:CaptionInfo sec:type="srt">http://192.168.1.3:9999/video.srt</sec:CaptionInfo> + //var res = container.OwnerDocument.CreateElement("SEC", "CaptionInfoEx"); //res.InnerText = info.Url; @@ -201,6 +204,16 @@ namespace MediaBrowser.Dlna.Didl //res.SetAttribute("type", info.Format.ToLower()); //container.AppendChild(res); } + else if (string.Equals(subtitleMode, "smi", StringComparison.OrdinalIgnoreCase)) + { + var res = container.OwnerDocument.CreateElement(string.Empty, "res", NS_DIDL); + + res.InnerText = info.Url; + + res.SetAttribute("protocolInfo", "http-get:*:smi/caption:*"); + + container.AppendChild(res); + } else { var res = container.OwnerDocument.CreateElement(string.Empty, "res", NS_DIDL); diff --git a/MediaBrowser.Server.Implementations/LiveTv/Listings/SchedulesDirect.cs b/MediaBrowser.Server.Implementations/LiveTv/Listings/SchedulesDirect.cs index c536d0e83..230a79775 100644 --- a/MediaBrowser.Server.Implementations/LiveTv/Listings/SchedulesDirect.cs +++ b/MediaBrowser.Server.Implementations/LiveTv/Listings/SchedulesDirect.cs @@ -132,6 +132,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv.Listings { StreamReader innerReader = new StreamReader(innerResponse.Content); responseString = innerReader.ReadToEnd(); + var programDetails = _jsonSerializer.DeserializeFromString<List<ScheduleDirect.ProgramDetails>>( responseString); @@ -142,10 +143,10 @@ namespace MediaBrowser.Server.Implementations.LiveTv.Listings 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); + //_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) @@ -244,7 +245,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv.Listings 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; @@ -268,43 +269,17 @@ namespace MediaBrowser.Server.Implementations.LiveTv.Listings } } - 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 = 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; - } - } if (details.episodeTitle150 != null) { - episodeTitle = ((episodeTitle ?? string.Empty) + " " + details.episodeTitle150).Trim(); + episodeTitle = details.episodeTitle150; } - var imageLink = ""; + string imageUrl = null; if (details.hasImageArtwork) { - imageLink = details.images; + imageUrl = details.images; } var showType = details.showType ?? string.Empty; @@ -313,7 +288,6 @@ namespace MediaBrowser.Server.Implementations.LiveTv.Listings { ChannelId = channel, Id = newID, - Overview = desc, StartDate = startAt, EndDate = endAt, Name = details.titles[0].title120 ?? "Unkown", @@ -321,23 +295,48 @@ namespace MediaBrowser.Server.Implementations.LiveTv.Listings CommunityRating = null, EpisodeTitle = episodeTitle, Audio = audioType, - IsHD = hdtv, IsRepeat = repeat, IsSeries = showType.IndexOf("series", StringComparison.OrdinalIgnoreCase) != -1, - ImageUrl = imageLink, + ImageUrl = imageUrl, HasImage = details.hasImageArtwork, - IsNews = false, - IsKids = false, + IsKids = string.Equals(details.audience, "children", StringComparison.OrdinalIgnoreCase), IsSports = showType.IndexOf("sports", StringComparison.OrdinalIgnoreCase) != -1, - IsLive = false, IsMovie = showType.IndexOf("movie", StringComparison.OrdinalIgnoreCase) != -1 || showType.IndexOf("film", StringComparison.OrdinalIgnoreCase) != -1, - IsPremiere = false, ShowId = programInfo.programID }; + if (programInfo.videoProperties != null) + { + info.IsHD = programInfo.videoProperties.Contains("hdtv", StringComparer.OrdinalIgnoreCase); + } + + if (details.contentRating != null && details.contentRating.Count > 0) + { + info.OfficialRating = details.contentRating[0].code.Replace("TV", "TV-").Replace("--", "-"); + } + + if (details.descriptions != null) + { + if (details.descriptions.description1000 != null) + { + info.Overview = details.descriptions.description1000[0].description; + } + else if (details.descriptions.description100 != null) + { + info.ShortOverview = details.descriptions.description100[0].description; + } + } + if (info.IsSeries) { info.SeriesId = programInfo.programID.Substring(0, 10); + + if (details.metadata != null) + { + var gracenote = details.metadata.Find(x => x.Gracenote != null).Gracenote; + info.SeasonNumber = gracenote.season; + info.EpisodeNumber = gracenote.episode; + } } if (!string.IsNullOrWhiteSpace(details.originalAirDate)) @@ -349,8 +348,8 @@ namespace MediaBrowser.Server.Implementations.LiveTv.Listings { info.Genres = details.genres.Where(g => !string.IsNullOrWhiteSpace(g)).ToList(); info.IsNews = details.genres.Contains("news", StringComparer.OrdinalIgnoreCase); - info.IsKids = false; } + return info; } @@ -888,6 +887,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv.Listings public class ProgramDetails { + public string audience { get; set; } public string programID { get; set; } public List<Title> titles { get; set; } public EventDetails eventDetails { get; set; } diff --git a/MediaBrowser.Server.Implementations/LiveTv/LiveTvManager.cs b/MediaBrowser.Server.Implementations/LiveTv/LiveTvManager.cs index 4c44f5c3b..26007f145 100644 --- a/MediaBrowser.Server.Implementations/LiveTv/LiveTvManager.cs +++ b/MediaBrowser.Server.Implementations/LiveTv/LiveTvManager.cs @@ -632,6 +632,9 @@ namespace MediaBrowser.Server.Implementations.LiveTv item.ProductionYear = info.ProductionYear; item.PremiereDate = item.PremiereDate ?? info.OriginalAirDate; + item.IndexNumber = info.EpisodeNumber; + item.ParentIndexNumber = info.SeasonNumber; + if (isNew) { await _libraryManager.CreateItem(item, cancellationToken).ConfigureAwait(false); @@ -641,24 +644,11 @@ namespace MediaBrowser.Server.Implementations.LiveTv await _libraryManager.UpdateItem(item, ItemUpdateType.MetadataImport, cancellationToken).ConfigureAwait(false); } - var maxStartDate = DateTime.UtcNow.AddDays(3); - - _providerManager.QueueRefresh(item.Id, new MetadataRefreshOptions - { - ImageRefreshMode = info.StartDate <= maxStartDate ? ImageRefreshMode.Default : ImageRefreshMode.ValidationOnly - }); + _providerManager.QueueRefresh(item.Id, new MetadataRefreshOptions()); return item; } - private void RefreshIfNeeded(LiveTvProgram program) - { - if (_refreshedPrograms.TryAdd(program.Id, program.Id)) - { - _providerManager.QueueRefresh(program.Id, new MetadataRefreshOptions()); - } - } - private async Task<Guid> CreateRecordingRecord(RecordingInfo info, string serviceName, CancellationToken cancellationToken) { var isNew = false; @@ -763,8 +753,6 @@ namespace MediaBrowser.Server.Implementations.LiveTv { var program = GetInternalProgram(id); - RefreshIfNeeded(program); - var dto = _dtoService.GetBaseItemDto(program, new DtoOptions(), user); await AddRecordingInfo(new[] { dto }, cancellationToken).ConfigureAwait(false); @@ -832,7 +820,6 @@ namespace MediaBrowser.Server.Implementations.LiveTv var returnArray = returnPrograms .Select(i => { - RefreshIfNeeded(i); return _dtoService.GetBaseItemDto(i, options, user); }) .ToArray(); @@ -907,11 +894,6 @@ namespace MediaBrowser.Server.Implementations.LiveTv var returnArray = programList.ToArray(); - foreach (var program in returnArray) - { - RefreshIfNeeded(program); - } - var result = new QueryResult<LiveTvProgram> { Items = returnArray, -- cgit v1.2.3 From e5aea2b622d36e38380ac7e97bfb653931253e77 Mon Sep 17 00:00:00 2001 From: Luke Pulverenti <luke.pulverenti@gmail.com> Date: Wed, 19 Aug 2015 12:43:23 -0400 Subject: pool tuners --- MediaBrowser.Controller/LiveTv/ITunerHost.cs | 6 +-- .../Movies/GenericMovieDbInfo.cs | 33 +++++++----- MediaBrowser.Providers/Omdb/OmdbItemProvider.cs | 4 +- MediaBrowser.Providers/Omdb/OmdbProvider.cs | 8 ++- .../LiveTv/EmbyTV/EmbyTV.cs | 8 +-- .../LiveTv/TunerHosts/HdHomerun/HdHomerunHost.cs | 61 ++++++++++++++++++++- .../LiveTv/TunerHosts/M3UTunerHost.cs | 62 +++++++++++++++++----- 7 files changed, 142 insertions(+), 40 deletions(-) (limited to 'MediaBrowser.Controller/LiveTv') diff --git a/MediaBrowser.Controller/LiveTv/ITunerHost.cs b/MediaBrowser.Controller/LiveTv/ITunerHost.cs index a6c8021d9..0d1852fe2 100644 --- a/MediaBrowser.Controller/LiveTv/ITunerHost.cs +++ b/MediaBrowser.Controller/LiveTv/ITunerHost.cs @@ -21,17 +21,15 @@ namespace MediaBrowser.Controller.LiveTv /// <summary> /// Gets the channels. /// </summary> - /// <param name="info">The information.</param> /// <param name="cancellationToken">The cancellation token.</param> /// <returns>Task<IEnumerable<ChannelInfo>>.</returns> - Task<IEnumerable<ChannelInfo>> GetChannels(TunerHostInfo info, CancellationToken cancellationToken); + Task<IEnumerable<ChannelInfo>> GetChannels(CancellationToken cancellationToken); /// <summary> /// Gets the tuner infos. /// </summary> - /// <param name="info">The information.</param> /// <param name="cancellationToken">The cancellation token.</param> /// <returns>Task<List<LiveTvTunerInfo>>.</returns> - Task<List<LiveTvTunerInfo>> GetTunerInfos(TunerHostInfo info, CancellationToken cancellationToken); + Task<List<LiveTvTunerInfo>> GetTunerInfos(CancellationToken cancellationToken); /// <summary> /// Gets the channel stream. /// </summary> diff --git a/MediaBrowser.Providers/Movies/GenericMovieDbInfo.cs b/MediaBrowser.Providers/Movies/GenericMovieDbInfo.cs index 5b5afc6c7..f5ee33d6b 100644 --- a/MediaBrowser.Providers/Movies/GenericMovieDbInfo.cs +++ b/MediaBrowser.Providers/Movies/GenericMovieDbInfo.cs @@ -185,18 +185,25 @@ namespace MediaBrowser.Providers.Movies //release date and certification are retrieved based on configured country and we fall back on US if not there and to minimun release date if still no match if (movieData.releases != null && movieData.releases.countries != null) { - var ourRelease = movieData.releases.countries.FirstOrDefault(c => c.iso_3166_1.Equals(preferredCountryCode, StringComparison.OrdinalIgnoreCase)) ?? new MovieDbProvider.Country(); - var usRelease = movieData.releases.countries.FirstOrDefault(c => c.iso_3166_1.Equals("US", StringComparison.OrdinalIgnoreCase)) ?? new MovieDbProvider.Country(); - var minimunRelease = movieData.releases.countries.OrderBy(c => c.release_date).FirstOrDefault() ?? new MovieDbProvider.Country(); - - var ratingPrefix = string.Equals(preferredCountryCode, "us", StringComparison.OrdinalIgnoreCase) ? "" : preferredCountryCode + "-"; - movie.OfficialRating = !string.IsNullOrEmpty(ourRelease.certification) - ? ratingPrefix + ourRelease.certification - : !string.IsNullOrEmpty(usRelease.certification) - ? usRelease.certification - : !string.IsNullOrEmpty(minimunRelease.certification) - ? minimunRelease.iso_3166_1 + "-" + minimunRelease.certification - : null; + var releases = movieData.releases.countries.Where(i => !string.IsNullOrWhiteSpace(i.certification)).ToList(); + + var ourRelease = releases.FirstOrDefault(c => c.iso_3166_1.Equals(preferredCountryCode, StringComparison.OrdinalIgnoreCase)); + var usRelease = releases.FirstOrDefault(c => c.iso_3166_1.Equals("US", StringComparison.OrdinalIgnoreCase)); + var minimunRelease = releases.OrderBy(c => c.release_date).FirstOrDefault(); + + if (ourRelease != null) + { + var ratingPrefix = string.Equals(preferredCountryCode, "us", StringComparison.OrdinalIgnoreCase) ? "" : preferredCountryCode + "-"; + movie.OfficialRating = ratingPrefix + ourRelease.certification; + } + else if (usRelease != null) + { + movie.OfficialRating = usRelease.certification; + } + else if (minimunRelease != null) + { + movie.OfficialRating = minimunRelease.iso_3166_1 + "-" + minimunRelease.certification; + } } if (!string.IsNullOrWhiteSpace(movieData.release_date)) @@ -232,7 +239,7 @@ namespace MediaBrowser.Providers.Movies } resultItem.ResetPeople(); - + //Actors, Directors, Writers - all in People //actors come from cast if (movieData.casts != null && movieData.casts.cast != null) diff --git a/MediaBrowser.Providers/Omdb/OmdbItemProvider.cs b/MediaBrowser.Providers/Omdb/OmdbItemProvider.cs index dffabd83c..36e7697d7 100644 --- a/MediaBrowser.Providers/Omdb/OmdbItemProvider.cs +++ b/MediaBrowser.Providers/Omdb/OmdbItemProvider.cs @@ -172,7 +172,7 @@ namespace MediaBrowser.Providers.Omdb result.Item.SetProviderId(MetadataProviders.Imdb, imdbId); result.HasMetadata = true; - await new OmdbProvider(_jsonSerializer, _httpClient).Fetch(result.Item, imdbId, info.MetadataLanguage, cancellationToken).ConfigureAwait(false); + await new OmdbProvider(_jsonSerializer, _httpClient).Fetch(result.Item, imdbId, info.MetadataLanguage, info.MetadataCountryCode, cancellationToken).ConfigureAwait(false); } return result; @@ -211,7 +211,7 @@ namespace MediaBrowser.Providers.Omdb result.Item.SetProviderId(MetadataProviders.Imdb, imdbId); result.HasMetadata = true; - await new OmdbProvider(_jsonSerializer, _httpClient).Fetch(result.Item, imdbId, info.MetadataLanguage, cancellationToken).ConfigureAwait(false); + await new OmdbProvider(_jsonSerializer, _httpClient).Fetch(result.Item, imdbId, info.MetadataLanguage, info.MetadataCountryCode, cancellationToken).ConfigureAwait(false); } return result; diff --git a/MediaBrowser.Providers/Omdb/OmdbProvider.cs b/MediaBrowser.Providers/Omdb/OmdbProvider.cs index 9208031f3..c7ce57fca 100644 --- a/MediaBrowser.Providers/Omdb/OmdbProvider.cs +++ b/MediaBrowser.Providers/Omdb/OmdbProvider.cs @@ -28,7 +28,7 @@ namespace MediaBrowser.Providers.Omdb Current = this; } - public async Task Fetch(BaseItem item, string imdbId, string language, CancellationToken cancellationToken) + public async Task Fetch(BaseItem item, string imdbId, string language, string country, CancellationToken cancellationToken) { if (string.IsNullOrWhiteSpace(imdbId)) { @@ -55,7 +55,11 @@ namespace MediaBrowser.Providers.Omdb if (string.Equals(language, "en", StringComparison.OrdinalIgnoreCase)) { item.Name = result.Title; - item.OfficialRating = result.Rated; + + if (string.Equals(country, "us", StringComparison.OrdinalIgnoreCase)) + { + item.OfficialRating = result.Rated; + } } int year; diff --git a/MediaBrowser.Server.Implementations/LiveTv/EmbyTV/EmbyTV.cs b/MediaBrowser.Server.Implementations/LiveTv/EmbyTV/EmbyTV.cs index cd166ddd3..eb23fab80 100644 --- a/MediaBrowser.Server.Implementations/LiveTv/EmbyTV/EmbyTV.cs +++ b/MediaBrowser.Server.Implementations/LiveTv/EmbyTV/EmbyTV.cs @@ -88,11 +88,11 @@ namespace MediaBrowser.Server.Implementations.LiveTv.EmbyTV var status = new LiveTvServiceStatusInfo(); var list = new List<LiveTvTunerInfo>(); - foreach (var hostInstance in GetTunerHosts()) + foreach (var hostInstance in _liveTvManager.TunerHosts) { try { - var tuners = await hostInstance.Item1.GetTunerInfos(hostInstance.Item2, cancellationToken).ConfigureAwait(false); + var tuners = await hostInstance.GetTunerInfos(cancellationToken).ConfigureAwait(false); list.AddRange(tuners); } @@ -120,11 +120,11 @@ namespace MediaBrowser.Server.Implementations.LiveTv.EmbyTV var list = new List<ChannelInfo>(); - foreach (var hostInstance in GetTunerHosts()) + foreach (var hostInstance in _liveTvManager.TunerHosts) { try { - var channels = await hostInstance.Item1.GetChannels(hostInstance.Item2, cancellationToken).ConfigureAwait(false); + var channels = await hostInstance.GetChannels(cancellationToken).ConfigureAwait(false); list.AddRange(channels); } diff --git a/MediaBrowser.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunHost.cs b/MediaBrowser.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunHost.cs index 35f77abcb..7607d5b9d 100644 --- a/MediaBrowser.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunHost.cs +++ b/MediaBrowser.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunHost.cs @@ -49,7 +49,46 @@ namespace MediaBrowser.Server.Implementations.LiveTv.TunerHosts.HdHomerun private const string ChannelIdPrefix = "hdhr_"; - public async Task<IEnumerable<ChannelInfo>> GetChannels(TunerHostInfo info, CancellationToken cancellationToken) + private List<TunerHostInfo> GetTunerHosts() + { + return GetConfiguration().TunerHosts + .Where(i => i.IsEnabled && string.Equals(i.Type, Type, StringComparison.OrdinalIgnoreCase)) + .ToList(); + } + + public async Task<IEnumerable<ChannelInfo>> GetChannels(CancellationToken cancellationToken) + { + var list = new List<ChannelInfo>(); + + var hosts = GetTunerHosts(); + + var ipAddresses = new List<string>(); + + foreach (var host in hosts) + { + var ip = GetApiUrl(host, false); + + if (ipAddresses.Contains(ip, StringComparer.OrdinalIgnoreCase)) + { + continue; + } + + try + { + list.AddRange(await GetChannels(host, cancellationToken).ConfigureAwait(false)); + } + catch (Exception ex) + { + _logger.ErrorException("Error getting channel list", ex); + } + + ipAddresses.Add(ip); + } + + return list; + } + + private async Task<IEnumerable<ChannelInfo>> GetChannels(TunerHostInfo info, CancellationToken cancellationToken) { var options = new HttpRequestOptions { @@ -146,6 +185,26 @@ namespace MediaBrowser.Server.Implementations.LiveTv.TunerHosts.HdHomerun } } + public async Task<List<LiveTvTunerInfo>> GetTunerInfos(CancellationToken cancellationToken) + { + var list = new List<LiveTvTunerInfo>(); + + foreach (var host in GetConfiguration().TunerHosts + .Where(i => i.IsEnabled && string.Equals(i.Type, Type, StringComparison.OrdinalIgnoreCase))) + { + try + { + list.AddRange(await GetTunerInfos(host, cancellationToken).ConfigureAwait(false)); + } + catch (Exception ex) + { + _logger.ErrorException("Error getting tuner info", ex); + } + } + + return list; + } + private string GetApiUrl(TunerHostInfo info, bool isPlayback) { var url = info.Url; diff --git a/MediaBrowser.Server.Implementations/LiveTv/TunerHosts/M3UTunerHost.cs b/MediaBrowser.Server.Implementations/LiveTv/TunerHosts/M3UTunerHost.cs index 0755d2a39..ec05cefd5 100644 --- a/MediaBrowser.Server.Implementations/LiveTv/TunerHosts/M3UTunerHost.cs +++ b/MediaBrowser.Server.Implementations/LiveTv/TunerHosts/M3UTunerHost.cs @@ -4,6 +4,7 @@ using MediaBrowser.Controller.LiveTv; using MediaBrowser.Model.Dto; using MediaBrowser.Model.Entities; using MediaBrowser.Model.LiveTv; +using MediaBrowser.Model.Logging; using MediaBrowser.Model.MediaInfo; using System; using System.Collections.Generic; @@ -27,20 +28,52 @@ namespace MediaBrowser.Server.Implementations.LiveTv.TunerHosts } private readonly IConfigurationManager _config; + private readonly ILogger _logger; - public M3UTunerHost(IConfigurationManager config) + public M3UTunerHost(IConfigurationManager config, ILogger logger) { _config = config; + _logger = logger; } - public Task<IEnumerable<ChannelInfo>> GetChannels(TunerHostInfo info, CancellationToken cancellationToken) + private List<TunerHostInfo> GetTunerHosts() { - var urlHash = info.Url.GetMD5().ToString("N"); - + return GetConfiguration().TunerHosts + .Where(i => i.IsEnabled && string.Equals(i.Type, Type, StringComparison.OrdinalIgnoreCase)) + .ToList(); + } + + public async Task<IEnumerable<ChannelInfo>> GetChannels(CancellationToken cancellationToken) + { + var list = new List<ChannelInfo>(); + + var urls = GetTunerHosts().Select(i => i.Url) + .Where(i => !string.IsNullOrWhiteSpace(i)) + .Distinct(StringComparer.OrdinalIgnoreCase); + + foreach (var url in urls) + { + try + { + list.AddRange(await GetChannels(url, cancellationToken).ConfigureAwait(false)); + } + catch (Exception ex) + { + _logger.ErrorException("Error getting channel list", ex); + } + } + + return list; + } + + private Task<IEnumerable<ChannelInfo>> GetChannels(string url, CancellationToken cancellationToken) + { + var urlHash = url.GetMD5().ToString("N"); + int position = 0; string line; // Read the file and display it line by line. - var file = new StreamReader(info.Url); + var file = new StreamReader(url); var channels = new List<M3UChannel>(); while ((line = file.ReadLine()) != null) { @@ -105,19 +138,20 @@ namespace MediaBrowser.Server.Implementations.LiveTv.TunerHosts return Task.FromResult((IEnumerable<ChannelInfo>)channels); } - public Task<List<LiveTvTunerInfo>> GetTunerInfos(TunerHostInfo info, CancellationToken cancellationToken) + public Task<List<LiveTvTunerInfo>> GetTunerInfos(CancellationToken cancellationToken) { - var list = new List<LiveTvTunerInfo>(); - - list.Add(new LiveTvTunerInfo() + var list = GetConfiguration().TunerHosts + .Where(i => i.IsEnabled && string.Equals(i.Type, Type, StringComparison.OrdinalIgnoreCase)) + .Select(i => new LiveTvTunerInfo() { Name = Name, SourceType = Type, Status = LiveTvTunerStatus.Available, - Id = info.Url.GetMD5().ToString("N"), - Url = info.Url - }); - + Id = i.Url.GetMD5().ToString("N"), + Url = i.Url + }) + .ToList(); + return Task.FromResult(list); } @@ -136,7 +170,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv.TunerHosts channelId = channelId.Substring(urlHash.Length); - var channels = await GetChannels(info, cancellationToken).ConfigureAwait(false); + var channels = await GetChannels(info.Url, cancellationToken).ConfigureAwait(false); var m3uchannels = channels.Cast<M3UChannel>(); var channel = m3uchannels.FirstOrDefault(c => c.Id == channelId); if (channel != null) -- cgit v1.2.3 From 8c32aefb53ed6684a9cd492662460e0fe7b83b0f Mon Sep 17 00:00:00 2001 From: Luke Pulverenti <luke.pulverenti@gmail.com> Date: Wed, 19 Aug 2015 15:25:18 -0400 Subject: update tuner pooling --- MediaBrowser.Controller/LiveTv/ITunerHost.cs | 6 +- .../LiveTv/EmbyTV/EmbyTV.cs | 39 +------- .../LiveTv/TunerHosts/BaseTunerHost.cs | 107 ++++++++++++++++++++- .../LiveTv/TunerHosts/HdHomerun/HdHomerunHost.cs | 15 ++- .../LiveTv/TunerHosts/M3UTunerHost.cs | 28 ++++-- 5 files changed, 146 insertions(+), 49 deletions(-) (limited to 'MediaBrowser.Controller/LiveTv') diff --git a/MediaBrowser.Controller/LiveTv/ITunerHost.cs b/MediaBrowser.Controller/LiveTv/ITunerHost.cs index 0d1852fe2..bedbcffe3 100644 --- a/MediaBrowser.Controller/LiveTv/ITunerHost.cs +++ b/MediaBrowser.Controller/LiveTv/ITunerHost.cs @@ -33,20 +33,18 @@ namespace MediaBrowser.Controller.LiveTv /// <summary> /// Gets the channel stream. /// </summary> - /// <param name="info">The information.</param> /// <param name="channelId">The channel identifier.</param> /// <param name="streamId">The stream identifier.</param> /// <param name="cancellationToken">The cancellation token.</param> /// <returns>Task<MediaSourceInfo>.</returns> - Task<MediaSourceInfo> GetChannelStream(TunerHostInfo info, string channelId, string streamId, CancellationToken cancellationToken); + Task<MediaSourceInfo> GetChannelStream(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); + Task<List<MediaSourceInfo>> GetChannelStreamMediaSources(string channelId, CancellationToken cancellationToken); /// <summary> /// Validates the specified information. /// </summary> diff --git a/MediaBrowser.Server.Implementations/LiveTv/EmbyTV/EmbyTV.cs b/MediaBrowser.Server.Implementations/LiveTv/EmbyTV/EmbyTV.cs index eb23fab80..7fbff31b2 100644 --- a/MediaBrowser.Server.Implementations/LiveTv/EmbyTV/EmbyTV.cs +++ b/MediaBrowser.Server.Implementations/LiveTv/EmbyTV/EmbyTV.cs @@ -1,6 +1,5 @@ using MediaBrowser.Common; using MediaBrowser.Common.Configuration; -using MediaBrowser.Common.Extensions; using MediaBrowser.Common.IO; using MediaBrowser.Common.Net; using MediaBrowser.Controller.Drawing; @@ -13,7 +12,6 @@ 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; @@ -161,20 +159,6 @@ namespace MediaBrowser.Server.Implementations.LiveTv.EmbyTV return GetChannelsAsync(false, cancellationToken); } - 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)); - - return provider == null ? null : new Tuple<ITunerHost, TunerHostInfo>(provider, i); - }) - .Where(i => i != null) - .ToList(); - } - public Task CancelSeriesTimerAsync(string timerId, CancellationToken cancellationToken) { var timers = _timerProvider.GetAll().Where(i => string.Equals(i.SeriesTimerId, timerId, StringComparison.OrdinalIgnoreCase)); @@ -409,22 +393,12 @@ namespace MediaBrowser.Server.Implementations.LiveTv.EmbyTV { _logger.Info("Streaming Channel " + channelId); - foreach (var hostInstance in GetTunerHosts()) + foreach (var hostInstance in _liveTvManager.TunerHosts) { - 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, channelId, streamId, cancellationToken).ConfigureAwait(false); + mediaSourceInfo = await hostInstance.GetChannelStream(channelId, streamId, cancellationToken).ConfigureAwait(false); } catch (Exception e) { @@ -443,16 +417,11 @@ namespace MediaBrowser.Server.Implementations.LiveTv.EmbyTV public async Task<List<MediaSourceInfo>> GetChannelStreamMediaSources(string channelId, CancellationToken cancellationToken) { - foreach (var hostInstance in GetTunerHosts()) + foreach (var hostInstance in _liveTvManager.TunerHosts) { try { - var sources = await hostInstance.Item1.GetChannelStreamMediaSources(hostInstance.Item2, channelId, cancellationToken).ConfigureAwait(false); - - foreach (var source in sources) - { - source.Id = hostInstance.Item2.Id + "-" + source.Id; - } + var sources = await hostInstance.GetChannelStreamMediaSources(channelId, cancellationToken).ConfigureAwait(false); if (sources.Count > 0) { diff --git a/MediaBrowser.Server.Implementations/LiveTv/TunerHosts/BaseTunerHost.cs b/MediaBrowser.Server.Implementations/LiveTv/TunerHosts/BaseTunerHost.cs index b3c8bce26..fb6fa9084 100644 --- a/MediaBrowser.Server.Implementations/LiveTv/TunerHosts/BaseTunerHost.cs +++ b/MediaBrowser.Server.Implementations/LiveTv/TunerHosts/BaseTunerHost.cs @@ -1,5 +1,6 @@ using MediaBrowser.Common.Configuration; using MediaBrowser.Controller.LiveTv; +using MediaBrowser.Model.Dto; using MediaBrowser.Model.LiveTv; using MediaBrowser.Model.Logging; using System; @@ -83,11 +84,115 @@ namespace MediaBrowser.Server.Implementations.LiveTv.TunerHosts return list; } + protected abstract Task<List<MediaSourceInfo>> GetChannelStreamMediaSources(TunerHostInfo tuner, string channelId, CancellationToken cancellationToken); + + public async Task<List<MediaSourceInfo>> GetChannelStreamMediaSources(string channelId, CancellationToken cancellationToken) + { + if (IsValidChannelId(channelId)) + { + var hosts = GetTunerHosts(); + + var hostsWithChannel = new List<TunerHostInfo>(); + + foreach (var host in hosts) + { + var channels = await GetChannels(host, true, cancellationToken).ConfigureAwait(false); + + if (channels.Any(i => string.Equals(i.Id, channelId, StringComparison.OrdinalIgnoreCase))) + { + hostsWithChannel.Add(host); + } + } + + foreach (var host in hostsWithChannel) + { + // Check to make sure the tuner is available + // If there's only one tuner, don't bother with the check and just let the tuner be the one to throw an error + if (hostsWithChannel.Count > 1 && !await IsAvailable(host, channelId, cancellationToken).ConfigureAwait(false)) + { + Logger.Error("Tuner is not currently available"); + continue; + } + + var mediaSources = await GetChannelStreamMediaSources(host, channelId, cancellationToken).ConfigureAwait(false); + + // Prefix the id with the host Id so that we can easily find it + foreach (var mediaSource in mediaSources) + { + mediaSource.Id = host.Id + mediaSource.Id; + } + + return mediaSources; + } + } + + return new List<MediaSourceInfo>(); + } + + protected abstract Task<MediaSourceInfo> GetChannelStream(TunerHostInfo tuner, string channelId, string streamId, CancellationToken cancellationToken); + + public async Task<MediaSourceInfo> GetChannelStream(string channelId, string streamId, CancellationToken cancellationToken) + { + if (IsValidChannelId(channelId)) + { + var hosts = GetTunerHosts(); + + var hostsWithChannel = new List<TunerHostInfo>(); + + foreach (var host in hosts) + { + if (string.IsNullOrWhiteSpace(streamId)) + { + var channels = await GetChannels(host, true, cancellationToken).ConfigureAwait(false); + + if (channels.Any(i => string.Equals(i.Id, channelId, StringComparison.OrdinalIgnoreCase))) + { + hostsWithChannel.Add(host); + } + } + else if (streamId.StartsWith(host.Id, StringComparison.OrdinalIgnoreCase)) + { + hostsWithChannel = new List<TunerHostInfo> { host }; + streamId = streamId.Substring(host.Id.Length); + break; + } + } + + foreach (var host in hostsWithChannel) + { + // Check to make sure the tuner is available + // If there's only one tuner, don't bother with the check and just let the tuner be the one to throw an error + // If a streamId is specified then availibility has already been checked in GetChannelStreamMediaSources + if (string.IsNullOrWhiteSpace(streamId) && hostsWithChannel.Count > 1) + { + if (!await IsAvailable(host, channelId, cancellationToken).ConfigureAwait(false)) + { + Logger.Error("Tuner is not currently available"); + continue; + } + } + + var stream = await GetChannelStream(host, channelId, streamId, cancellationToken).ConfigureAwait(false); + + if (stream != null) + { + return null; + } + } + } + + throw new LiveTvConflictException(); + } + + protected abstract Task<bool> IsAvailable(TunerHostInfo tuner, string channelId, CancellationToken cancellationToken); + + protected abstract bool IsValidChannelId(string channelId); + protected LiveTvOptions GetConfiguration() { return Config.GetConfiguration<LiveTvOptions>("livetv"); } - + private class ChannelCache { public DateTime Date; diff --git a/MediaBrowser.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunHost.cs b/MediaBrowser.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunHost.cs index a07ccd3a4..307a61588 100644 --- a/MediaBrowser.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunHost.cs +++ b/MediaBrowser.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunHost.cs @@ -329,7 +329,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv.TunerHosts.HdHomerun return mediaSource; } - public async Task<List<MediaSourceInfo>> GetChannelStreamMediaSources(TunerHostInfo info, string channelId, CancellationToken cancellationToken) + protected override async Task<List<MediaSourceInfo>> GetChannelStreamMediaSources(TunerHostInfo info, string channelId, CancellationToken cancellationToken) { var list = new List<MediaSourceInfo>(); @@ -364,7 +364,12 @@ namespace MediaBrowser.Server.Implementations.LiveTv.TunerHosts.HdHomerun return list; } - public async Task<MediaSourceInfo> GetChannelStream(TunerHostInfo info, string channelId, string streamId, CancellationToken cancellationToken) + protected override bool IsValidChannelId(string channelId) + { + return channelId.StartsWith(ChannelIdPrefix, StringComparison.OrdinalIgnoreCase); + } + + protected override async Task<MediaSourceInfo> GetChannelStream(TunerHostInfo info, string channelId, string streamId, CancellationToken cancellationToken) { if (!channelId.StartsWith(ChannelIdPrefix, StringComparison.OrdinalIgnoreCase)) { @@ -379,5 +384,11 @@ namespace MediaBrowser.Server.Implementations.LiveTv.TunerHosts.HdHomerun { await GetChannels(info, false, CancellationToken.None).ConfigureAwait(false); } + + protected override async Task<bool> IsAvailable(TunerHostInfo tuner, string channelId, CancellationToken cancellationToken) + { + // TODO + return true; + } } } diff --git a/MediaBrowser.Server.Implementations/LiveTv/TunerHosts/M3UTunerHost.cs b/MediaBrowser.Server.Implementations/LiveTv/TunerHosts/M3UTunerHost.cs index 0dc170cfd..bd0feb573 100644 --- a/MediaBrowser.Server.Implementations/LiveTv/TunerHosts/M3UTunerHost.cs +++ b/MediaBrowser.Server.Implementations/LiveTv/TunerHosts/M3UTunerHost.cs @@ -17,7 +17,8 @@ namespace MediaBrowser.Server.Implementations.LiveTv.TunerHosts { public class M3UTunerHost : BaseTunerHost, ITunerHost { - public M3UTunerHost(IConfigurationManager config, ILogger logger) : base(config, logger) + public M3UTunerHost(IConfigurationManager config, ILogger logger) + : base(config, logger) { } @@ -31,6 +32,8 @@ namespace MediaBrowser.Server.Implementations.LiveTv.TunerHosts get { return "M3U Tuner"; } } + private const string ChannelIdPrefix = "m3u_"; + protected override async Task<IEnumerable<ChannelInfo>> GetChannelsInternal(TunerHostInfo info, CancellationToken cancellationToken) { var url = info.Url; @@ -88,7 +91,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv.TunerHosts switch (list[0]) { case "tvg-id": - channels.Last().Id = urlHash + list[1]; + channels.Last().Id = ChannelIdPrefix + urlHash + list[1]; channels.Last().Number = list[1]; break; case "tvg-name": @@ -117,19 +120,20 @@ namespace MediaBrowser.Server.Implementations.LiveTv.TunerHosts Url = i.Url }) .ToList(); - + return Task.FromResult(list); } - public async Task<MediaSourceInfo> GetChannelStream(TunerHostInfo info, string channelId, string streamId, CancellationToken cancellationToken) + protected override async Task<MediaSourceInfo> GetChannelStream(TunerHostInfo info, string channelId, string streamId, CancellationToken cancellationToken) { var urlHash = info.Url.GetMD5().ToString("N"); - if (!channelId.StartsWith(urlHash, StringComparison.OrdinalIgnoreCase)) + var prefix = ChannelIdPrefix + urlHash; + if (!channelId.StartsWith(prefix, StringComparison.OrdinalIgnoreCase)) { return null; } - channelId = channelId.Substring(urlHash.Length); + channelId = channelId.Substring(prefix.Length); var channels = await GetChannels(info, true, cancellationToken).ConfigureAwait(false); var m3uchannels = channels.Cast<M3UChannel>(); @@ -196,9 +200,19 @@ namespace MediaBrowser.Server.Implementations.LiveTv.TunerHosts } } - public Task<List<MediaSourceInfo>> GetChannelStreamMediaSources(TunerHostInfo info, string channelId, CancellationToken cancellationToken) + protected override bool IsValidChannelId(string channelId) + { + return channelId.StartsWith(ChannelIdPrefix, StringComparison.OrdinalIgnoreCase); + } + + protected override Task<List<MediaSourceInfo>> GetChannelStreamMediaSources(TunerHostInfo info, string channelId, CancellationToken cancellationToken) { throw new NotImplementedException(); } + + protected override Task<bool> IsAvailable(TunerHostInfo tuner, string channelId, CancellationToken cancellationToken) + { + return Task.FromResult(true); + } } } -- cgit v1.2.3 From 6d206bb9dcc457b573e5e5dc36651ff1246b52d9 Mon Sep 17 00:00:00 2001 From: Luke Pulverenti <luke.pulverenti@gmail.com> Date: Thu, 20 Aug 2015 19:55:23 -0400 Subject: update recording save path --- MediaBrowser.Controller/Entities/Movies/Movie.cs | 13 ++++++-- MediaBrowser.Controller/LiveTv/LiveTvProgram.cs | 10 ++++++ .../LiveTv/LiveTvVideoRecording.cs | 11 +++++++ .../LiveTv/EmbyTV/EmbyTV.cs | 13 ++++++++ .../LiveTv/EmbyTV/RecordingHelper.cs | 38 +++++++++++++--------- 5 files changed, 67 insertions(+), 18 deletions(-) (limited to 'MediaBrowser.Controller/LiveTv') diff --git a/MediaBrowser.Controller/Entities/Movies/Movie.cs b/MediaBrowser.Controller/Entities/Movies/Movie.cs index fc07f6778..083ec0cb4 100644 --- a/MediaBrowser.Controller/Entities/Movies/Movie.cs +++ b/MediaBrowser.Controller/Entities/Movies/Movie.cs @@ -100,16 +100,23 @@ namespace MediaBrowser.Controller.Entities.Movies /// <returns>System.String.</returns> protected override string CreateUserDataKey() { - var key = this.GetProviderId(MetadataProviders.Tmdb); + var key = GetMovieUserDataKey(this); if (string.IsNullOrWhiteSpace(key)) { - key = this.GetProviderId(MetadataProviders.Imdb); + key = base.CreateUserDataKey(); } + return key; + } + + public static string GetMovieUserDataKey(BaseItem movie) + { + var key = movie.GetProviderId(MetadataProviders.Tmdb); + if (string.IsNullOrWhiteSpace(key)) { - key = base.CreateUserDataKey(); + key = movie.GetProviderId(MetadataProviders.Imdb); } return key; diff --git a/MediaBrowser.Controller/LiveTv/LiveTvProgram.cs b/MediaBrowser.Controller/LiveTv/LiveTvProgram.cs index b54a7aaee..14944d36f 100644 --- a/MediaBrowser.Controller/LiveTv/LiveTvProgram.cs +++ b/MediaBrowser.Controller/LiveTv/LiveTvProgram.cs @@ -1,4 +1,5 @@ using MediaBrowser.Controller.Entities; +using MediaBrowser.Controller.Entities.Movies; using MediaBrowser.Controller.Providers; using MediaBrowser.Model.Configuration; using MediaBrowser.Model.LiveTv; @@ -17,6 +18,15 @@ namespace MediaBrowser.Controller.LiveTv /// <returns>System.String.</returns> protected override string CreateUserDataKey() { + if (IsMovie) + { + var key = Movie.GetMovieUserDataKey(this); + + if (!string.IsNullOrWhiteSpace(key)) + { + return key; + } + } return GetClientTypeName() + "-" + Name; } diff --git a/MediaBrowser.Controller/LiveTv/LiveTvVideoRecording.cs b/MediaBrowser.Controller/LiveTv/LiveTvVideoRecording.cs index aaaff6bdb..960f8054a 100644 --- a/MediaBrowser.Controller/LiveTv/LiveTvVideoRecording.cs +++ b/MediaBrowser.Controller/LiveTv/LiveTvVideoRecording.cs @@ -1,4 +1,5 @@ using MediaBrowser.Controller.Entities; +using MediaBrowser.Controller.Entities.Movies; using MediaBrowser.Model.Configuration; using MediaBrowser.Model.Dto; using MediaBrowser.Model.Entities; @@ -40,6 +41,16 @@ namespace MediaBrowser.Controller.LiveTv /// <returns>System.String.</returns> protected override string CreateUserDataKey() { + if (IsMovie) + { + var key = Movie.GetMovieUserDataKey(this); + + if (!string.IsNullOrWhiteSpace(key)) + { + return key; + } + } + var name = GetClientTypeName(); if (!string.IsNullOrEmpty(ProgramId)) diff --git a/MediaBrowser.Server.Implementations/LiveTv/EmbyTV/EmbyTV.cs b/MediaBrowser.Server.Implementations/LiveTv/EmbyTV/EmbyTV.cs index 355597fcf..ebb5037d0 100644 --- a/MediaBrowser.Server.Implementations/LiveTv/EmbyTV/EmbyTV.cs +++ b/MediaBrowser.Server.Implementations/LiveTv/EmbyTV/EmbyTV.cs @@ -495,10 +495,23 @@ namespace MediaBrowser.Server.Implementations.LiveTv.EmbyTV var info = GetProgramInfoFromCache(timer.ChannelId, timer.ProgramId); var recordPath = RecordingPath; + if (info.IsMovie) { recordPath = Path.Combine(recordPath, "Movies", _fileSystem.GetValidFilename(info.Name)); } + else if (info.IsSeries) + { + recordPath = Path.Combine(recordPath, "Series", _fileSystem.GetValidFilename(info.Name)); + } + else if (info.IsKids) + { + recordPath = Path.Combine(recordPath, "Kids", _fileSystem.GetValidFilename(info.Name)); + } + else if (info.IsSports) + { + recordPath = Path.Combine(recordPath, "Sports", _fileSystem.GetValidFilename(info.Name)); + } else { recordPath = Path.Combine(recordPath, "TV", _fileSystem.GetValidFilename(info.Name)); diff --git a/MediaBrowser.Server.Implementations/LiveTv/EmbyTV/RecordingHelper.cs b/MediaBrowser.Server.Implementations/LiveTv/EmbyTV/RecordingHelper.cs index 09a5a3912..1b8cd2e61 100644 --- a/MediaBrowser.Server.Implementations/LiveTv/EmbyTV/RecordingHelper.cs +++ b/MediaBrowser.Server.Implementations/LiveTv/EmbyTV/RecordingHelper.cs @@ -1,6 +1,7 @@ using MediaBrowser.Common.Extensions; using MediaBrowser.Controller.LiveTv; using System; +using System.Globalization; namespace MediaBrowser.Server.Implementations.LiveTv.EmbyTV { @@ -36,26 +37,33 @@ namespace MediaBrowser.Server.Implementations.LiveTv.EmbyTV { if (info == null) { - return (timer.ProgramId + ".ts"); + return timer.ProgramId + ".ts"; } - var fancyName = info.Name; - if (info.ProductionYear != null) - { - fancyName += "_(" + info.ProductionYear + ")"; - } - if (info.IsSeries && !string.IsNullOrWhiteSpace(info.EpisodeTitle)) - { - fancyName += "_" + info.EpisodeTitle.Replace("Season: ", "S").Replace(" Episode: ", "E"); - } - if (info.IsHD ?? false) + + var name = info.Name; + + if (info.IsSeries) { - fancyName += "_HD"; + if (info.SeasonNumber.HasValue && info.EpisodeNumber.HasValue) + { + name += string.Format(" S{0}E{1}", info.SeasonNumber.Value.ToString("00", CultureInfo.InvariantCulture), info.EpisodeNumber.Value.ToString("00", CultureInfo.InvariantCulture)); + } + else if (info.OriginalAirDate.HasValue) + { + name += " " + info.OriginalAirDate.Value.ToString("yyyy-MM-dd"); + } + else if (!string.IsNullOrWhiteSpace(info.EpisodeTitle)) + { + name += " " + info.EpisodeTitle; + } } - if (info.OriginalAirDate != null) + + else if (info.ProductionYear != null) { - fancyName += "_" + info.OriginalAirDate.Value.ToString("yyyy-MM-dd"); + name += " (" + info.ProductionYear + ")"; } - return fancyName + ".ts"; + + return name + ".ts"; } } } -- cgit v1.2.3 From ddcebc4ff704d08e5f0a4dab5d14fe40e244b6d1 Mon Sep 17 00:00:00 2001 From: Luke Pulverenti <luke.pulverenti@gmail.com> Date: Thu, 20 Aug 2015 22:36:30 -0400 Subject: add tv suggestions --- MediaBrowser.Api/Library/LibraryService.cs | 126 ++++++++++++++++++++- MediaBrowser.Api/Movies/MoviesService.cs | 29 ++++- MediaBrowser.Api/Movies/TrailersService.cs | 39 +------ MediaBrowser.Api/Music/AlbumsService.cs | 50 ++++++++ MediaBrowser.Api/UserLibrary/GenresService.cs | 2 - .../Entities/IHasProgramAttributes.cs | 1 + MediaBrowser.Controller/LiveTv/ILiveTvRecording.cs | 1 - MediaBrowser.Model/ApiClient/IApiClient.cs | 48 +------- MediaBrowser.Model/Dto/BaseItemDto.cs | 9 ++ .../LiveTv/EmbyTV/EmbyTV.cs | 4 +- .../LiveTv/EmbyTV/RecordingHelper.cs | 7 +- 11 files changed, 217 insertions(+), 99 deletions(-) (limited to 'MediaBrowser.Controller/LiveTv') diff --git a/MediaBrowser.Api/Library/LibraryService.cs b/MediaBrowser.Api/Library/LibraryService.cs index 50c4ad14f..945e803b2 100644 --- a/MediaBrowser.Api/Library/LibraryService.cs +++ b/MediaBrowser.Api/Library/LibraryService.cs @@ -1,4 +1,7 @@ -using MediaBrowser.Controller.Activity; +using MediaBrowser.Api.Movies; +using MediaBrowser.Api.Music; +using MediaBrowser.Controller.Activity; +using MediaBrowser.Controller.Channels; using MediaBrowser.Controller.Dto; using MediaBrowser.Controller.Entities; using MediaBrowser.Controller.Entities.Audio; @@ -9,7 +12,9 @@ using MediaBrowser.Controller.LiveTv; using MediaBrowser.Controller.Localization; using MediaBrowser.Controller.Net; using MediaBrowser.Controller.Persistence; +using MediaBrowser.Controller.TV; using MediaBrowser.Model.Activity; +using MediaBrowser.Model.Channels; using MediaBrowser.Model.Dto; using MediaBrowser.Model.Entities; using MediaBrowser.Model.Querying; @@ -238,6 +243,12 @@ namespace MediaBrowser.Api.Library public string Id { get; set; } } + [Route("/Items/{Id}/Similar", "GET", Summary = "Downloads item media")] + [Authenticated(Roles = "download")] + public class GetSimilarItems : BaseGetSimilarItemsFromItem + { + } + /// <summary> /// Class LibraryService /// </summary> @@ -257,12 +268,14 @@ namespace MediaBrowser.Api.Library private readonly IActivityManager _activityManager; private readonly ILocalizationManager _localization; private readonly ILiveTvManager _liveTv; + private readonly IChannelManager _channelManager; + private readonly ITVSeriesManager _tvManager; /// <summary> /// Initializes a new instance of the <see cref="LibraryService" /> class. /// </summary> public LibraryService(IItemRepository itemRepo, ILibraryManager libraryManager, IUserManager userManager, - IDtoService dtoService, IUserDataManager userDataManager, IAuthorizationContext authContext, IActivityManager activityManager, ILocalizationManager localization, ILiveTvManager liveTv) + IDtoService dtoService, IUserDataManager userDataManager, IAuthorizationContext authContext, IActivityManager activityManager, ILocalizationManager localization, ILiveTvManager liveTv, IChannelManager channelManager, ITVSeriesManager tvManager) { _itemRepo = itemRepo; _libraryManager = libraryManager; @@ -273,6 +286,115 @@ namespace MediaBrowser.Api.Library _activityManager = activityManager; _localization = localization; _liveTv = liveTv; + _channelManager = channelManager; + _tvManager = tvManager; + } + + public object Get(GetSimilarItems request) + { + var user = !string.IsNullOrWhiteSpace(request.UserId) ? _userManager.GetUserById(request.UserId) : null; + + var item = string.IsNullOrEmpty(request.Id) ? + (!string.IsNullOrWhiteSpace(request.UserId) ? user.RootFolder : + _libraryManager.RootFolder) : _libraryManager.GetItemById(request.Id); + + if (item is Game) + { + return new GamesService(_userManager, _userDataManager, _libraryManager, _itemRepo, _dtoService) + { + AuthorizationContext = AuthorizationContext, + Logger = Logger, + Request = Request, + SessionContext = SessionContext, + ResultFactory = ResultFactory + + }.Get(new GetSimilarGames + { + Fields = request.Fields, + Id = request.Id, + Limit = request.Limit, + UserId = request.UserId + }); + } + if (item is MusicAlbum) + { + return new AlbumsService(_userManager, _userDataManager, _libraryManager, _itemRepo, _dtoService) + { + AuthorizationContext = AuthorizationContext, + Logger = Logger, + Request = Request, + SessionContext = SessionContext, + ResultFactory = ResultFactory + + }.Get(new GetSimilarAlbums + { + Fields = request.Fields, + Id = request.Id, + Limit = request.Limit, + UserId = request.UserId + }); + } + if (item is MusicArtist) + { + return new AlbumsService(_userManager, _userDataManager, _libraryManager, _itemRepo, _dtoService) + { + AuthorizationContext = AuthorizationContext, + Logger = Logger, + Request = Request, + SessionContext = SessionContext, + ResultFactory = ResultFactory + + }.Get(new GetSimilarArtists + { + Fields = request.Fields, + Id = request.Id, + Limit = request.Limit, + UserId = request.UserId + }); + } + + var program = item as IHasProgramAttributes; + var channelItem = item as ChannelVideoItem; + + if (item is Movie || (program != null && program.IsMovie) || (channelItem != null && channelItem.ContentType == ChannelMediaContentType.Movie && channelItem.ContentType == ChannelMediaContentType.MovieExtra)) + { + return new MoviesService(_userManager, _userDataManager, _libraryManager, _itemRepo, _dtoService, _channelManager) + { + AuthorizationContext = AuthorizationContext, + Logger = Logger, + Request = Request, + SessionContext = SessionContext, + ResultFactory = ResultFactory + + }.Get(new GetSimilarMovies + { + Fields = request.Fields, + Id = request.Id, + Limit = request.Limit, + UserId = request.UserId + }); + } + + if (item is Series || (program != null && program.IsSeries) || (channelItem != null && channelItem.ContentType == ChannelMediaContentType.Episode)) + { + return new TvShowsService(_userManager, _userDataManager, _libraryManager, _itemRepo, _dtoService, _tvManager) + { + AuthorizationContext = AuthorizationContext, + Logger = Logger, + Request = Request, + SessionContext = SessionContext, + ResultFactory = ResultFactory + + }.Get(new GetSimilarShows + { + Fields = request.Fields, + Id = request.Id, + Limit = request.Limit, + UserId = request.UserId + }); + } + + return new ItemsResult(); } public object Get(GetMediaFolders request) diff --git a/MediaBrowser.Api/Movies/MoviesService.cs b/MediaBrowser.Api/Movies/MoviesService.cs index 97e9aa9c8..fe8bae1a5 100644 --- a/MediaBrowser.Api/Movies/MoviesService.cs +++ b/MediaBrowser.Api/Movies/MoviesService.cs @@ -28,6 +28,14 @@ namespace MediaBrowser.Api.Movies { } + /// <summary> + /// Class GetSimilarTrailers + /// </summary> + [Route("/Trailers/{Id}/Similar", "GET", Summary = "Finds movies and trailers similar to a given trailer.")] + public class GetSimilarTrailers : BaseGetSimilarItemsFromItem + { + } + [Route("/Movies/Recommendations", "GET", Summary = "Gets movie recommendations")] public class GetMovieRecommendations : IReturn<RecommendationDto[]>, IHasItemFields { @@ -117,6 +125,17 @@ namespace MediaBrowser.Api.Movies return ToOptimizedSerializedResultUsingCache(result); } + public async Task<object> Get(GetSimilarTrailers request) + { + var result = await GetSimilarItemsResult( + // Strip out secondary versions + request, item => (item is Movie) && !((Video)item).PrimaryVersionId.HasValue, + + SimilarItemsHelper.GetSimiliarityScore).ConfigureAwait(false); + + return ToOptimizedSerializedResultUsingCache(result); + } + public async Task<object> Get(GetMovieRecommendations request) { var user = _userManager.GetUserById(request.UserId); @@ -126,7 +145,7 @@ namespace MediaBrowser.Api.Movies movies = _libraryManager.ReplaceVideosWithPrimaryVersions(movies); var listEligibleForCategories = new List<BaseItem>(); - var listEligibleForSuggestion = new List<BaseItem> (); + var listEligibleForSuggestion = new List<BaseItem>(); var list = movies.ToList(); @@ -159,7 +178,7 @@ namespace MediaBrowser.Api.Movies var dtoOptions = GetDtoOptions(request); dtoOptions.Fields = request.GetItemFields().ToList(); - + var result = GetRecommendationCategories(user, listEligibleForCategories, listEligibleForSuggestion, request.CategoryLimit, request.ItemLimit, dtoOptions); return ToOptimizedResult(result); @@ -174,14 +193,14 @@ namespace MediaBrowser.Api.Movies _libraryManager.RootFolder) : _libraryManager.GetItemById(request.Id); Func<BaseItem, bool> filter = i => i.Id != item.Id && includeInSearch(i); - + var inputItems = user == null ? _libraryManager.RootFolder.GetRecursiveChildren(filter) : user.RootFolder.GetRecursiveChildren(user, filter); var list = inputItems.ToList(); - if (item is Movie && user != null && user.Configuration.IncludeTrailersInSuggestions) + if (user != null && user.Configuration.IncludeTrailersInSuggestions) { var trailerResult = await _channelManager.GetAllMediaInternal(new AllChannelMediaQuery { @@ -224,7 +243,7 @@ namespace MediaBrowser.Api.Movies } var dtoOptions = GetDtoOptions(request); - + var result = new ItemsResult { Items = _dtoService.GetBaseItemDtos(returnItems, dtoOptions, user).ToArray(), diff --git a/MediaBrowser.Api/Movies/TrailersService.cs b/MediaBrowser.Api/Movies/TrailersService.cs index 0847fc7ed..ed197911a 100644 --- a/MediaBrowser.Api/Movies/TrailersService.cs +++ b/MediaBrowser.Api/Movies/TrailersService.cs @@ -2,15 +2,12 @@ using MediaBrowser.Controller.Channels; using MediaBrowser.Controller.Dto; using MediaBrowser.Controller.Entities; -using MediaBrowser.Controller.Entities.Movies; using MediaBrowser.Controller.Library; using MediaBrowser.Controller.Net; -using MediaBrowser.Controller.Persistence; using MediaBrowser.Model.Channels; using MediaBrowser.Model.Entities; using MediaBrowser.Model.Querying; using ServiceStack; -using System; using System.Collections.Generic; using System.Linq; using System.Threading; @@ -18,14 +15,6 @@ using System.Threading.Tasks; namespace MediaBrowser.Api.Movies { - /// <summary> - /// Class GetSimilarTrailers - /// </summary> - [Route("/Trailers/{Id}/Similar", "GET", Summary = "Finds movies and trailers similar to a given trailer.")] - public class GetSimilarTrailers : BaseGetSimilarItemsFromItem - { - } - [Route("/Trailers", "GET", Summary = "Finds movies and trailers similar to a given trailer.")] public class Getrailers : BaseItemsRequest, IReturn<ItemsResult> { @@ -51,7 +40,6 @@ namespace MediaBrowser.Api.Movies /// </summary> private readonly ILibraryManager _libraryManager; - private readonly IItemRepository _itemRepo; private readonly IDtoService _dtoService; private readonly IChannelManager _channelManager; @@ -61,40 +49,15 @@ namespace MediaBrowser.Api.Movies /// <param name="userManager">The user manager.</param> /// <param name="userDataRepository">The user data repository.</param> /// <param name="libraryManager">The library manager.</param> - public TrailersService(IUserManager userManager, IUserDataManager userDataRepository, ILibraryManager libraryManager, IItemRepository itemRepo, IDtoService dtoService, IChannelManager channelManager) + public TrailersService(IUserManager userManager, IUserDataManager userDataRepository, ILibraryManager libraryManager, IDtoService dtoService, IChannelManager channelManager) { _userManager = userManager; _userDataRepository = userDataRepository; _libraryManager = libraryManager; - _itemRepo = itemRepo; _dtoService = dtoService; _channelManager = channelManager; } - /// <summary> - /// Gets the specified request. - /// </summary> - /// <param name="request">The request.</param> - /// <returns>System.Object.</returns> - public object Get(GetSimilarTrailers request) - { - var dtoOptions = GetDtoOptions(request); - - var result = SimilarItemsHelper.GetSimilarItemsResult(dtoOptions, _userManager, - _itemRepo, - _libraryManager, - _userDataRepository, - _dtoService, - Logger, - - // Strip out secondary versions - request, item => (item is Movie) && !((Video)item).PrimaryVersionId.HasValue, - - SimilarItemsHelper.GetSimiliarityScore); - - return ToOptimizedSerializedResultUsingCache(result); - } - public async Task<object> Get(Getrailers request) { var user = !string.IsNullOrWhiteSpace(request.UserId) ? _userManager.GetUserById(request.UserId) : null; diff --git a/MediaBrowser.Api/Music/AlbumsService.cs b/MediaBrowser.Api/Music/AlbumsService.cs index ea87c3ad3..548598d42 100644 --- a/MediaBrowser.Api/Music/AlbumsService.cs +++ b/MediaBrowser.Api/Music/AlbumsService.cs @@ -4,6 +4,7 @@ using MediaBrowser.Controller.Entities.Audio; using MediaBrowser.Controller.Library; using MediaBrowser.Controller.Net; using MediaBrowser.Controller.Persistence; +using MediaBrowser.Model.Querying; using ServiceStack; using System; using System.Collections.Generic; @@ -16,6 +17,11 @@ namespace MediaBrowser.Api.Music { } + [Route("/Artists/{Id}/Similar", "GET", Summary = "Finds albums similar to a given album.")] + public class GetSimilarArtists : BaseGetSimilarItemsFromItem + { + } + [Authenticated] public class AlbumsService : BaseApiService { @@ -44,6 +50,17 @@ namespace MediaBrowser.Api.Music _dtoService = dtoService; } + public object Get(GetSimilarArtists request) + { + var result = GetSimilarItemsResult( + + request, + + SimilarItemsHelper.GetSimiliarityScore); + + return ToOptimizedSerializedResultUsingCache(result); + } + /// <summary> /// Gets the specified request. /// </summary> @@ -65,6 +82,39 @@ namespace MediaBrowser.Api.Music return ToOptimizedSerializedResultUsingCache(result); } + private ItemsResult GetSimilarItemsResult(BaseGetSimilarItemsFromItem request, Func<BaseItem, List<PersonInfo>, List<PersonInfo>, BaseItem, int> getSimilarityScore) + { + var user = !string.IsNullOrWhiteSpace(request.UserId) ? _userManager.GetUserById(request.UserId) : null; + + var item = string.IsNullOrEmpty(request.Id) ? + (!string.IsNullOrWhiteSpace(request.UserId) ? user.RootFolder : + _libraryManager.RootFolder) : _libraryManager.GetItemById(request.Id); + + var inputItems = _libraryManager.GetArtists(user.RootFolder.GetRecursiveChildren(user, i => i is IHasArtist).OfType<IHasArtist>()); + + var list = inputItems.ToList(); + + var items = SimilarItemsHelper.GetSimilaritems(item, _libraryManager, list, getSimilarityScore).ToList(); + + IEnumerable<BaseItem> returnItems = items; + + if (request.Limit.HasValue) + { + returnItems = returnItems.Take(request.Limit.Value); + } + + var dtoOptions = GetDtoOptions(request); + + var result = new ItemsResult + { + Items = _dtoService.GetBaseItemDtos(returnItems, dtoOptions, user).ToArray(), + + TotalRecordCount = items.Count + }; + + return result; + } + /// <summary> /// Gets the album similarity score. /// </summary> diff --git a/MediaBrowser.Api/UserLibrary/GenresService.cs b/MediaBrowser.Api/UserLibrary/GenresService.cs index 9e56907da..d383bd0ad 100644 --- a/MediaBrowser.Api/UserLibrary/GenresService.cs +++ b/MediaBrowser.Api/UserLibrary/GenresService.cs @@ -1,12 +1,10 @@ using MediaBrowser.Controller.Dto; using MediaBrowser.Controller.Entities; -using MediaBrowser.Controller.Entities.Audio; using MediaBrowser.Controller.Library; using MediaBrowser.Controller.Net; using MediaBrowser.Controller.Persistence; using MediaBrowser.Model.Dto; using MediaBrowser.Model.Entities; -using MediaBrowser.Model.Querying; using ServiceStack; using System; using System.Collections.Generic; diff --git a/MediaBrowser.Controller/Entities/IHasProgramAttributes.cs b/MediaBrowser.Controller/Entities/IHasProgramAttributes.cs index 391c8f7a7..9938a4489 100644 --- a/MediaBrowser.Controller/Entities/IHasProgramAttributes.cs +++ b/MediaBrowser.Controller/Entities/IHasProgramAttributes.cs @@ -11,6 +11,7 @@ namespace MediaBrowser.Controller.Entities bool IsKids { get; set; } bool IsRepeat { get; set; } bool? IsHD { get; set; } + bool IsSeries { get; set; } bool IsLive { get; set; } bool IsPremiere { get; set; } ProgramAudio? Audio { get; set; } diff --git a/MediaBrowser.Controller/LiveTv/ILiveTvRecording.cs b/MediaBrowser.Controller/LiveTv/ILiveTvRecording.cs index 9fc60beb9..ba0b82a0b 100644 --- a/MediaBrowser.Controller/LiveTv/ILiveTvRecording.cs +++ b/MediaBrowser.Controller/LiveTv/ILiveTvRecording.cs @@ -37,7 +37,6 @@ namespace MediaBrowser.Controller.LiveTv string ExternalId { get; set; } string EpisodeTitle { get; set; } - bool IsSeries { get; set; } string SeriesTimerId { get; set; } RecordingStatus Status { get; set; } DateTime? EndDate { get; set; } diff --git a/MediaBrowser.Model/ApiClient/IApiClient.cs b/MediaBrowser.Model/ApiClient/IApiClient.cs index e52e7535b..6d441ccf8 100644 --- a/MediaBrowser.Model/ApiClient/IApiClient.cs +++ b/MediaBrowser.Model/ApiClient/IApiClient.cs @@ -353,39 +353,7 @@ namespace MediaBrowser.Model.ApiClient /// <param name="query">The query.</param> /// <param name="cancellationToken">The cancellation token.</param> /// <returns>Task{ItemsResult}.</returns> - Task<ItemsResult> GetSimilarMoviesAsync(SimilarItemsQuery query, CancellationToken cancellationToken = default(CancellationToken)); - - /// <summary> - /// Gets the similar trailers async. - /// </summary> - /// <param name="query">The query.</param> - /// <param name="cancellationToken">The cancellation token.</param> - /// <returns>Task{ItemsResult}.</returns> - Task<ItemsResult> GetSimilarTrailersAsync(SimilarItemsQuery query, CancellationToken cancellationToken = default(CancellationToken)); - - /// <summary> - /// Gets the similar series async. - /// </summary> - /// <param name="query">The query.</param> - /// <param name="cancellationToken">The cancellation token.</param> - /// <returns>Task{ItemsResult}.</returns> - Task<ItemsResult> GetSimilarSeriesAsync(SimilarItemsQuery query, CancellationToken cancellationToken = default(CancellationToken)); - - /// <summary> - /// Gets the similar albums async. - /// </summary> - /// <param name="query">The query.</param> - /// <param name="cancellationToken">The cancellation token.</param> - /// <returns>Task{ItemsResult}.</returns> - Task<ItemsResult> GetSimilarAlbumsAsync(SimilarItemsQuery query, CancellationToken cancellationToken = default(CancellationToken)); - - /// <summary> - /// Gets the similar games async. - /// </summary> - /// <param name="query">The query.</param> - /// <param name="cancellationToken">The cancellation token.</param> - /// <returns>Task{ItemsResult}.</returns> - Task<ItemsResult> GetSimilarGamesAsync(SimilarItemsQuery query, CancellationToken cancellationToken = default(CancellationToken)); + Task<ItemsResult> GetSimilarItemsAsync(SimilarItemsQuery query, CancellationToken cancellationToken = default(CancellationToken)); /// <summary> /// Gets the people async. @@ -442,20 +410,6 @@ namespace MediaBrowser.Model.ApiClient /// <returns>Task{ItemsResult}.</returns> Task<ItemsResult> GetGenresAsync(ItemsByNameQuery query); - /// <summary> - /// Gets the music genres async. - /// </summary> - /// <param name="query">The query.</param> - /// <returns>Task{ItemsResult}.</returns> - Task<ItemsResult> GetMusicGenresAsync(ItemsByNameQuery query); - - /// <summary> - /// Gets the game genres async. - /// </summary> - /// <param name="query">The query.</param> - /// <returns>Task{ItemsResult}.</returns> - Task<ItemsResult> GetGameGenresAsync(ItemsByNameQuery query); - /// <summary> /// Gets the studios async. /// </summary> diff --git a/MediaBrowser.Model/Dto/BaseItemDto.cs b/MediaBrowser.Model/Dto/BaseItemDto.cs index aa68e09a0..ac8fa3370 100644 --- a/MediaBrowser.Model/Dto/BaseItemDto.cs +++ b/MediaBrowser.Model/Dto/BaseItemDto.cs @@ -1081,6 +1081,15 @@ namespace MediaBrowser.Model.Dto get { return StringHelper.EqualsIgnoreCase(Type, "Studio"); } } + [IgnoreDataMember] + public bool SupportsSimilarItems + { + get + { + return IsType("Movie") || IsType("Series") || IsType("MusicAlbum") || IsType("MusicArtist") || IsType("Program") || IsType("Recording") || IsType("ChannelVideoItem") || IsType("Game"); + } + } + /// <summary> /// Occurs when [property changed]. /// </summary> diff --git a/MediaBrowser.Server.Implementations/LiveTv/EmbyTV/EmbyTV.cs b/MediaBrowser.Server.Implementations/LiveTv/EmbyTV/EmbyTV.cs index ebb5037d0..200c6c9a6 100644 --- a/MediaBrowser.Server.Implementations/LiveTv/EmbyTV/EmbyTV.cs +++ b/MediaBrowser.Server.Implementations/LiveTv/EmbyTV/EmbyTV.cs @@ -517,7 +517,9 @@ namespace MediaBrowser.Server.Implementations.LiveTv.EmbyTV recordPath = Path.Combine(recordPath, "TV", _fileSystem.GetValidFilename(info.Name)); } - recordPath = Path.Combine(recordPath, _fileSystem.GetValidFilename(RecordingHelper.GetRecordingName(timer, info))); + var recordingFileName = _fileSystem.GetValidFilename(RecordingHelper.GetRecordingName(timer, info)) + ".ts"; + + recordPath = Path.Combine(recordPath, recordingFileName); Directory.CreateDirectory(Path.GetDirectoryName(recordPath)); var recording = _recordingProvider.GetAll().FirstOrDefault(x => string.Equals(x.ProgramId, info.Id, StringComparison.OrdinalIgnoreCase)); diff --git a/MediaBrowser.Server.Implementations/LiveTv/EmbyTV/RecordingHelper.cs b/MediaBrowser.Server.Implementations/LiveTv/EmbyTV/RecordingHelper.cs index 1b8cd2e61..f8f65c6d5 100644 --- a/MediaBrowser.Server.Implementations/LiveTv/EmbyTV/RecordingHelper.cs +++ b/MediaBrowser.Server.Implementations/LiveTv/EmbyTV/RecordingHelper.cs @@ -37,7 +37,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv.EmbyTV { if (info == null) { - return timer.ProgramId + ".ts"; + return timer.ProgramId; } var name = info.Name; @@ -52,7 +52,8 @@ namespace MediaBrowser.Server.Implementations.LiveTv.EmbyTV { name += " " + info.OriginalAirDate.Value.ToString("yyyy-MM-dd"); } - else if (!string.IsNullOrWhiteSpace(info.EpisodeTitle)) + + if (!string.IsNullOrWhiteSpace(info.EpisodeTitle)) { name += " " + info.EpisodeTitle; } @@ -63,7 +64,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv.EmbyTV name += " (" + info.ProductionYear + ")"; } - return name + ".ts"; + return name; } } } -- cgit v1.2.3 From 4307c67b5e518ef2514740b0a874f5832f31e537 Mon Sep 17 00:00:00 2001 From: Luke Pulverenti <luke.pulverenti@gmail.com> Date: Fri, 21 Aug 2015 15:25:35 -0400 Subject: update setup wizard --- MediaBrowser.Api/LiveTv/LiveTvService.cs | 21 +++++++++++++++ .../LiveTv/IHasRegistrationInfo.cs | 15 +++++++++++ MediaBrowser.Controller/LiveTv/ILiveTvManager.cs | 10 +++++++ .../MediaBrowser.Controller.csproj | 1 + .../LiveTv/EmbyTV/EmbyTV.cs | 31 +++++++++++++++++++--- .../LiveTv/LiveTvManager.cs | 29 ++++++++++++++++++++ 6 files changed, 103 insertions(+), 4 deletions(-) create mode 100644 MediaBrowser.Controller/LiveTv/IHasRegistrationInfo.cs (limited to 'MediaBrowser.Controller/LiveTv') diff --git a/MediaBrowser.Api/LiveTv/LiveTvService.cs b/MediaBrowser.Api/LiveTv/LiveTvService.cs index e55103230..c1f8ac3ea 100644 --- a/MediaBrowser.Api/LiveTv/LiveTvService.cs +++ b/MediaBrowser.Api/LiveTv/LiveTvService.cs @@ -456,6 +456,20 @@ namespace MediaBrowser.Api.LiveTv { } + [Route("/LiveTv/Registration", "GET")] + [Authenticated] + public class GetLiveTvRegistrationInfo : IReturn<MBRegistrationRecord> + { + [ApiMember(Name = "ChannelId", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET")] + public string ChannelId { get; set; } + + [ApiMember(Name = "ProgramId", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET")] + public string ProgramId { get; set; } + + [ApiMember(Name = "Feature", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET")] + public string Feature { get; set; } + } + public class LiveTvService : BaseApiService { private readonly ILiveTvManager _liveTvManager; @@ -471,6 +485,13 @@ namespace MediaBrowser.Api.LiveTv _httpClient = httpClient; } + public async Task<object> Get(GetLiveTvRegistrationInfo request) + { + var result = await _liveTvManager.GetRegistrationInfo(request.ChannelId, request.ProgramId, request.Feature).ConfigureAwait(false); + + return ToOptimizedResult(result); + } + public async Task<object> Get(GetSchedulesDirectCountries request) { // https://json.schedulesdirect.org/20141201/available/countries diff --git a/MediaBrowser.Controller/LiveTv/IHasRegistrationInfo.cs b/MediaBrowser.Controller/LiveTv/IHasRegistrationInfo.cs new file mode 100644 index 000000000..3626c18e5 --- /dev/null +++ b/MediaBrowser.Controller/LiveTv/IHasRegistrationInfo.cs @@ -0,0 +1,15 @@ +using MediaBrowser.Model.Entities; +using System.Threading.Tasks; + +namespace MediaBrowser.Controller.LiveTv +{ + public interface IHasRegistrationInfo + { + /// <summary> + /// Gets the registration information. + /// </summary> + /// <param name="feature">The feature.</param> + /// <returns>Task<MBRegistrationRecord>.</returns> + Task<MBRegistrationRecord> GetRegistrationInfo(string feature); + } +} diff --git a/MediaBrowser.Controller/LiveTv/ILiveTvManager.cs b/MediaBrowser.Controller/LiveTv/ILiveTvManager.cs index df09d39b2..2b121eeeb 100644 --- a/MediaBrowser.Controller/LiveTv/ILiveTvManager.cs +++ b/MediaBrowser.Controller/LiveTv/ILiveTvManager.cs @@ -2,6 +2,7 @@ using MediaBrowser.Controller.Dto; using MediaBrowser.Controller.Entities; using MediaBrowser.Model.Dto; +using MediaBrowser.Model.Entities; using MediaBrowser.Model.LiveTv; using MediaBrowser.Model.Querying; using System.Collections.Generic; @@ -362,5 +363,14 @@ namespace MediaBrowser.Controller.LiveTv /// <param name="location">The location.</param> /// <returns>Task<List<NameIdPair>>.</returns> Task<List<NameIdPair>> GetLineups(string providerType, string providerId, string country, string location); + + /// <summary> + /// Gets the registration information. + /// </summary> + /// <param name="channelId">The channel identifier.</param> + /// <param name="programId">The program identifier.</param> + /// <param name="feature">The feature.</param> + /// <returns>Task<MBRegistrationRecord>.</returns> + Task<MBRegistrationRecord> GetRegistrationInfo(string channelId, string programId, string feature); } } diff --git a/MediaBrowser.Controller/MediaBrowser.Controller.csproj b/MediaBrowser.Controller/MediaBrowser.Controller.csproj index b84fe3c71..24309734f 100644 --- a/MediaBrowser.Controller/MediaBrowser.Controller.csproj +++ b/MediaBrowser.Controller/MediaBrowser.Controller.csproj @@ -199,6 +199,7 @@ <Compile Include="Library\NameExtensions.cs" /> <Compile Include="Library\PlaybackStopEventArgs.cs" /> <Compile Include="Library\UserDataSaveEventArgs.cs" /> + <Compile Include="LiveTv\IHasRegistrationInfo.cs" /> <Compile Include="LiveTv\IListingsProvider.cs" /> <Compile Include="LiveTv\ILiveTvItem.cs" /> <Compile Include="LiveTv\ITunerHost.cs" /> diff --git a/MediaBrowser.Server.Implementations/LiveTv/EmbyTV/EmbyTV.cs b/MediaBrowser.Server.Implementations/LiveTv/EmbyTV/EmbyTV.cs index 200c6c9a6..708828d47 100644 --- a/MediaBrowser.Server.Implementations/LiveTv/EmbyTV/EmbyTV.cs +++ b/MediaBrowser.Server.Implementations/LiveTv/EmbyTV/EmbyTV.cs @@ -2,9 +2,11 @@ using MediaBrowser.Common.Configuration; using MediaBrowser.Common.IO; using MediaBrowser.Common.Net; +using MediaBrowser.Common.Security; using MediaBrowser.Controller.Drawing; using MediaBrowser.Controller.LiveTv; using MediaBrowser.Model.Dto; +using MediaBrowser.Model.Entities; using MediaBrowser.Model.Events; using MediaBrowser.Model.LiveTv; using MediaBrowser.Model.Logging; @@ -19,7 +21,7 @@ using System.Threading.Tasks; namespace MediaBrowser.Server.Implementations.LiveTv.EmbyTV { - public class EmbyTV : ILiveTvService, IDisposable + public class EmbyTV : ILiveTvService, IHasRegistrationInfo, IDisposable { private readonly IApplicationHost _appHpst; private readonly ILogger _logger; @@ -33,10 +35,11 @@ namespace MediaBrowser.Server.Implementations.LiveTv.EmbyTV private readonly LiveTvManager _liveTvManager; private readonly IFileSystem _fileSystem; + private readonly ISecurityManager _security; public static EmbyTV Current; - public EmbyTV(IApplicationHost appHost, ILogger logger, IJsonSerializer jsonSerializer, IHttpClient httpClient, IConfigurationManager config, ILiveTvManager liveTvManager, IFileSystem fileSystem) + public EmbyTV(IApplicationHost appHost, ILogger logger, IJsonSerializer jsonSerializer, IHttpClient httpClient, IConfigurationManager config, ILiveTvManager liveTvManager, IFileSystem fileSystem, ISecurityManager security) { Current = this; @@ -45,6 +48,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv.EmbyTV _httpClient = httpClient; _config = config; _fileSystem = fileSystem; + _security = security; _liveTvManager = (LiveTvManager)liveTvManager; _jsonSerializer = jsonSerializer; @@ -629,9 +633,14 @@ namespace MediaBrowser.Server.Implementations.LiveTv.EmbyTV .Where(i => string.Equals(i.SeriesTimerId, seriesTimer.Id, StringComparison.OrdinalIgnoreCase)) .ToList(); - foreach (var timer in newTimers) + var registration = await GetRegistrationInfo("seriesrecordings").ConfigureAwait(false); + + if (registration.IsValid) { - _timerProvider.AddOrUpdate(timer); + foreach (var timer in newTimers) + { + _timerProvider.AddOrUpdate(timer); + } } var newTimerIds = newTimers.Select(i => i.Id).ToList(); @@ -728,5 +737,19 @@ namespace MediaBrowser.Server.Implementations.LiveTv.EmbyTV pair.Value.Cancel(); } } + + public Task<MBRegistrationRecord> GetRegistrationInfo(string feature) + { + if (string.Equals(feature, "seriesrecordings", StringComparison.OrdinalIgnoreCase)) + { + return _security.GetRegistrationStatus("embytvseriesrecordings"); + } + + return Task.FromResult(new MBRegistrationRecord + { + IsValid = true, + IsRegistered = true + }); + } } } diff --git a/MediaBrowser.Server.Implementations/LiveTv/LiveTvManager.cs b/MediaBrowser.Server.Implementations/LiveTv/LiveTvManager.cs index cabe04f0f..4109617db 100644 --- a/MediaBrowser.Server.Implementations/LiveTv/LiveTvManager.cs +++ b/MediaBrowser.Server.Implementations/LiveTv/LiveTvManager.cs @@ -2286,5 +2286,34 @@ namespace MediaBrowser.Server.Implementations.LiveTv return provider.GetLineups(info, country, location); } } + + public Task<MBRegistrationRecord> GetRegistrationInfo(string channelId, string programId, string feature) + { + ILiveTvService service; + + if (string.IsNullOrWhiteSpace(programId)) + { + var channel = GetInternalChannel(channelId); + service = GetService(channel); + } + else + { + var program = GetInternalProgram(programId); + service = GetService(program); + } + + var hasRegistration = service as IHasRegistrationInfo; + + if (hasRegistration != null) + { + return hasRegistration.GetRegistrationInfo(feature); + } + + return Task.FromResult(new MBRegistrationRecord + { + IsValid = true, + IsRegistered = true + }); + } } } -- cgit v1.2.3 From de133cb8aa2b078ba653ee7c3e1cef4fd16996d6 Mon Sep 17 00:00:00 2001 From: Luke Pulverenti <luke.pulverenti@gmail.com> Date: Fri, 21 Aug 2015 22:59:10 -0400 Subject: update search --- MediaBrowser.Controller/Entities/BaseItem.cs | 1 + MediaBrowser.Controller/LiveTv/LiveTvProgram.cs | 6 + MediaBrowser.Controller/LiveTv/ProgramInfo.cs | 5 + .../Library/SearchEngine.cs | 272 ++++++--------------- .../Library/Validators/GameGenresValidator.cs | 27 +- .../Library/Validators/GenresValidator.cs | 27 +- .../Library/Validators/MusicGenresValidator.cs | 28 ++- .../Library/Validators/StudiosValidator.cs | 28 ++- .../LiveTv/EmbyTV/EmbyTV.cs | 18 +- .../LiveTv/Listings/SchedulesDirect.cs | 5 +- .../LiveTv/LiveTvManager.cs | 9 +- MediaBrowser.WebDashboard/Api/PackageCreator.cs | 2 +- .../MediaBrowser.WebDashboard.csproj | 18 +- 13 files changed, 224 insertions(+), 222 deletions(-) (limited to 'MediaBrowser.Controller/LiveTv') diff --git a/MediaBrowser.Controller/Entities/BaseItem.cs b/MediaBrowser.Controller/Entities/BaseItem.cs index c4917b0d1..cd5c39173 100644 --- a/MediaBrowser.Controller/Entities/BaseItem.cs +++ b/MediaBrowser.Controller/Entities/BaseItem.cs @@ -485,6 +485,7 @@ namespace MediaBrowser.Controller.Entities /// Gets or sets the parent. /// </summary> /// <value>The parent.</value> + [IgnoreDataMember] public Folder Parent { get diff --git a/MediaBrowser.Controller/LiveTv/LiveTvProgram.cs b/MediaBrowser.Controller/LiveTv/LiveTvProgram.cs index 14944d36f..12052905f 100644 --- a/MediaBrowser.Controller/LiveTv/LiveTvProgram.cs +++ b/MediaBrowser.Controller/LiveTv/LiveTvProgram.cs @@ -30,6 +30,12 @@ namespace MediaBrowser.Controller.LiveTv return GetClientTypeName() + "-" + Name; } + /// <summary> + /// Gets or sets the etag. + /// </summary> + /// <value>The etag.</value> + public string Etag { get; set; } + /// <summary> /// Id of the program. /// </summary> diff --git a/MediaBrowser.Controller/LiveTv/ProgramInfo.cs b/MediaBrowser.Controller/LiveTv/ProgramInfo.cs index 467264e7a..a6a3e6108 100644 --- a/MediaBrowser.Controller/LiveTv/ProgramInfo.cs +++ b/MediaBrowser.Controller/LiveTv/ProgramInfo.cs @@ -180,6 +180,11 @@ namespace MediaBrowser.Controller.LiveTv /// </summary> /// <value>The episode number.</value> public int? EpisodeNumber { get; set; } + /// <summary> + /// Gets or sets the etag. + /// </summary> + /// <value>The etag.</value> + public string Etag { get; set; } public ProgramInfo() { diff --git a/MediaBrowser.Server.Implementations/Library/SearchEngine.cs b/MediaBrowser.Server.Implementations/Library/SearchEngine.cs index 21e92786d..d4ff89b4f 100644 --- a/MediaBrowser.Server.Implementations/Library/SearchEngine.cs +++ b/MediaBrowser.Server.Implementations/Library/SearchEngine.cs @@ -33,26 +33,17 @@ namespace MediaBrowser.Server.Implementations.Library public async Task<QueryResult<SearchHintInfo>> GetSearchHints(SearchQuery query) { - IEnumerable<BaseItem> inputItems; - - Func<BaseItem, bool> filter = i => !(i is ICollectionFolder); - User user = null; if (string.IsNullOrWhiteSpace(query.UserId)) { - inputItems = _libraryManager.RootFolder.GetRecursiveChildren(filter); } else { user = _userManager.GetUserById(query.UserId); - - inputItems = user.RootFolder.GetRecursiveChildren(user, filter); } - inputItems = _libraryManager.ReplaceVideosWithPrimaryVersions(inputItems); - - var results = await GetSearchHints(inputItems, query, user).ConfigureAwait(false); + var results = await GetSearchHints(query, user).ConfigureAwait(false); var searchResultArray = results.ToArray(); results = searchResultArray; @@ -77,15 +68,22 @@ namespace MediaBrowser.Server.Implementations.Library }; } + private void AddIfMissing(List<string> list, string value) + { + if (!list.Contains(value, StringComparer.OrdinalIgnoreCase)) + { + list.Add(value); + } + } + /// <summary> /// Gets the search hints. /// </summary> - /// <param name="inputItems">The input items.</param> /// <param name="query">The query.</param> /// <param name="user">The user.</param> /// <returns>IEnumerable{SearchHintResult}.</returns> /// <exception cref="System.ArgumentNullException">searchTerm</exception> - private Task<IEnumerable<SearchHintInfo>> GetSearchHints(IEnumerable<BaseItem> inputItems, SearchQuery query, User user) + private Task<IEnumerable<SearchHintInfo>> GetSearchHints(SearchQuery query, User user) { var searchTerm = query.SearchTerm; @@ -100,207 +98,80 @@ namespace MediaBrowser.Server.Implementations.Library var hints = new List<Tuple<BaseItem, string, int>>(); - var items = inputItems.Where(i => !(i is MusicArtist)).ToList(); + var excludeItemTypes = new List<string>(); + var includeItemTypes = (query.IncludeItemTypes ?? new string[] { }).ToList(); - if (query.IncludeMedia) - { - var mediaItems = _libraryManager.GetItems(new InternalItemsQuery - { - NameContains = searchTerm, - ExcludeItemTypes = new[] - { - typeof (Person).Name, - typeof (Genre).Name, - typeof (MusicArtist).Name, - typeof (GameGenre).Name, - typeof (MusicGenre).Name, - typeof (Year).Name, - typeof (Studio).Name - }, - IncludeItemTypes = query.IncludeItemTypes - - }).Items; - - // Add search hints based on item name - hints.AddRange(mediaItems.Where(i => IncludeInSearch(i) && (user == null || i.IsVisibleStandalone(user)) && !(i is CollectionFolder)).Select(item => - { - var index = GetIndex(item.Name, searchTerm, terms); + excludeItemTypes.Add(typeof(Year).Name); - return new Tuple<BaseItem, string, int>(item, index.Item1, index.Item2); - })); - } - - if (query.IncludeArtists && (query.IncludeItemTypes.Length == 0 || query.IncludeItemTypes.Contains("MusicArtist", StringComparer.OrdinalIgnoreCase))) + if (query.IncludeGenres && (includeItemTypes.Count == 0 || includeItemTypes.Contains("Genre", StringComparer.OrdinalIgnoreCase))) { - // Find artists - var artists = items.OfType<Audio>() - .SelectMany(i => i.AllArtists) - .Where(i => !string.IsNullOrWhiteSpace(i)) - .DistinctNames() - .ToList(); - - foreach (var item in artists) + if (!query.IncludeMedia) { - var index = GetIndex(item, searchTerm, terms); - - if (index.Item2 != -1) - { - try - { - var artist = _libraryManager.GetArtist(item); - - hints.Add(new Tuple<BaseItem, string, int>(artist, index.Item1, index.Item2)); - } - catch (Exception ex) - { - _logger.ErrorException("Error getting {0}", ex, item); - } - } + AddIfMissing(includeItemTypes, typeof(Genre).Name); + AddIfMissing(includeItemTypes, typeof(GameGenre).Name); + AddIfMissing(includeItemTypes, typeof(MusicGenre).Name); } } - - if (query.IncludeGenres && (query.IncludeItemTypes.Length == 0 || query.IncludeItemTypes.Contains("Genre", StringComparer.OrdinalIgnoreCase))) + else { - // Find genres, from non-audio items - var genres = items.Where(i => !(i is IHasMusicGenres) && !(i is Game)) - .SelectMany(i => i.Genres) - .Where(i => !string.IsNullOrWhiteSpace(i)) - .Distinct(StringComparer.OrdinalIgnoreCase) - .ToList(); - - foreach (var item in genres) - { - var index = GetIndex(item, searchTerm, terms); - - if (index.Item2 != -1) - { - try - { - var genre = _libraryManager.GetGenre(item); - - hints.Add(new Tuple<BaseItem, string, int>(genre, index.Item1, index.Item2)); - } - catch (Exception ex) - { - _logger.ErrorException("Error getting {0}", ex, item); - } - } - } - - // Find music genres - var musicGenres = items.Where(i => i is IHasMusicGenres) - .SelectMany(i => i.Genres) - .Where(i => !string.IsNullOrWhiteSpace(i)) - .Distinct(StringComparer.OrdinalIgnoreCase) - .ToList(); + AddIfMissing(excludeItemTypes, typeof(Genre).Name); + AddIfMissing(excludeItemTypes, typeof(GameGenre).Name); + AddIfMissing(excludeItemTypes, typeof(MusicGenre).Name); + } - foreach (var item in musicGenres) + if (query.IncludePeople && (includeItemTypes.Count == 0 || includeItemTypes.Contains("People", StringComparer.OrdinalIgnoreCase))) + { + if (!query.IncludeMedia) { - var index = GetIndex(item, searchTerm, terms); - - if (index.Item2 != -1) - { - try - { - var genre = _libraryManager.GetMusicGenre(item); - - hints.Add(new Tuple<BaseItem, string, int>(genre, index.Item1, index.Item2)); - } - catch (Exception ex) - { - _logger.ErrorException("Error getting {0}", ex, item); - } - } + AddIfMissing(includeItemTypes, typeof(Person).Name); } + } + else + { + AddIfMissing(excludeItemTypes, typeof(Person).Name); + } - // Find music genres - var gameGenres = items.OfType<Game>() - .SelectMany(i => i.Genres) - .Where(i => !string.IsNullOrWhiteSpace(i)) - .Distinct(StringComparer.OrdinalIgnoreCase) - .ToList(); - - foreach (var item in gameGenres) + if (query.IncludeStudios && (includeItemTypes.Count == 0 || includeItemTypes.Contains("Studio", StringComparer.OrdinalIgnoreCase))) + { + if (!query.IncludeMedia) { - var index = GetIndex(item, searchTerm, terms); - - if (index.Item2 != -1) - { - try - { - var genre = _libraryManager.GetGameGenre(item); - - hints.Add(new Tuple<BaseItem, string, int>(genre, index.Item1, index.Item2)); - } - catch (Exception ex) - { - _logger.ErrorException("Error getting {0}", ex, item); - } - } + AddIfMissing(includeItemTypes, typeof(Studio).Name); } } - - if (query.IncludeStudios && (query.IncludeItemTypes.Length == 0 || query.IncludeItemTypes.Contains("Studio", StringComparer.OrdinalIgnoreCase))) + else { - // Find studios - var studios = items.SelectMany(i => i.Studios) - .Where(i => !string.IsNullOrWhiteSpace(i)) - .Distinct(StringComparer.OrdinalIgnoreCase) - .ToList(); + AddIfMissing(excludeItemTypes, typeof(Studio).Name); + } - foreach (var item in studios) + if (query.IncludeArtists && (includeItemTypes.Count == 0 || includeItemTypes.Contains("MusicArtist", StringComparer.OrdinalIgnoreCase))) + { + if (!query.IncludeMedia) { - var index = GetIndex(item, searchTerm, terms); - - if (index.Item2 != -1) - { - try - { - var studio = _libraryManager.GetStudio(item); - - hints.Add(new Tuple<BaseItem, string, int>(studio, index.Item1, index.Item2)); - } - catch (Exception ex) - { - _logger.ErrorException("Error getting {0}", ex, item); - } - } + AddIfMissing(includeItemTypes, typeof(MusicArtist).Name); } } + else + { + AddIfMissing(excludeItemTypes, typeof(MusicArtist).Name); + } - if (query.IncludePeople && (query.IncludeItemTypes.Length == 0 || query.IncludeItemTypes.Contains("Person", StringComparer.OrdinalIgnoreCase))) + var mediaItems = _libraryManager.GetItems(new InternalItemsQuery { - var itemIds = items.Select(i => i.Id).ToList(); + NameContains = searchTerm, + ExcludeItemTypes = excludeItemTypes.ToArray(), + IncludeItemTypes = includeItemTypes.ToArray(), + MaxParentalRating = user == null ? null : user.Policy.MaxParentalRating, + Limit = query.Limit.HasValue ? query.Limit * 3 : null - // Find persons - var persons = _libraryManager.GetPeople(new InternalPeopleQuery - { - NameContains = searchTerm - }) - .Where(i => itemIds.Contains(i.ItemId)) - .Select(i => i.Name) - .Distinct(StringComparer.OrdinalIgnoreCase) - .ToList(); - - foreach (var item in persons) - { - var index = GetIndex(item, searchTerm, terms); + }).Items; - if (index.Item2 != -1) - { - try - { - var person = _libraryManager.GetPerson(item); - - hints.Add(new Tuple<BaseItem, string, int>(person, index.Item1, index.Item2)); - } - catch (Exception ex) - { - _logger.ErrorException("Error getting {0}", ex, item); - } - } - } - } + // Add search hints based on item name + hints.AddRange(mediaItems.Where(i => IncludeInSearch(i) && IsVisible(i, user) && !(i is CollectionFolder)).Select(item => + { + var index = GetIndex(item.Name, searchTerm, terms); + + return new Tuple<BaseItem, string, int>(item, index.Item1, index.Item2); + })); var returnValue = hints.Where(i => i.Item3 >= 0).OrderBy(i => i.Item3).Select(i => new SearchHintInfo { @@ -311,13 +182,32 @@ namespace MediaBrowser.Server.Implementations.Library return Task.FromResult(returnValue); } + private bool IsVisible(BaseItem item, User user) + { + if (user == null) + { + return true; + } + + if (item is IItemByName) + { + var dual = item as IHasDualAccess; + if (dual == null || dual.IsAccessedByName) + { + return true; + } + } + + return item.IsVisibleStandalone(user); + } + private bool IncludeInSearch(BaseItem item) { var episode = item as Episode; if (episode != null) { - if (episode.IsVirtualUnaired || episode.IsMissingEpisode) + if (episode.IsMissingEpisode) { return false; } diff --git a/MediaBrowser.Server.Implementations/Library/Validators/GameGenresValidator.cs b/MediaBrowser.Server.Implementations/Library/Validators/GameGenresValidator.cs index fe2e6a114..ee06fecdf 100644 --- a/MediaBrowser.Server.Implementations/Library/Validators/GameGenresValidator.cs +++ b/MediaBrowser.Server.Implementations/Library/Validators/GameGenresValidator.cs @@ -1,4 +1,5 @@ -using MediaBrowser.Controller.Entities; +using System.Collections.Generic; +using MediaBrowser.Controller.Entities; using MediaBrowser.Controller.Library; using MediaBrowser.Model.Logging; using System; @@ -42,12 +43,16 @@ namespace MediaBrowser.Server.Implementations.Library.Validators var numComplete = 0; var count = items.Count; + var validIds = new List<Guid>(); + foreach (var name in items) { try { var itemByName = _libraryManager.GetGameGenre(name); + validIds.Add(itemByName.Id); + await itemByName.RefreshMetadata(cancellationToken).ConfigureAwait(false); } catch (OperationCanceledException) @@ -68,6 +73,26 @@ namespace MediaBrowser.Server.Implementations.Library.Validators progress.Report(percent); } + var allIds = _libraryManager.GetItemIds(new InternalItemsQuery + { + IncludeItemTypes = new[] { typeof(GameGenre).Name } + }); + + var invalidIds = allIds + .Except(validIds) + .ToList(); + + foreach (var id in invalidIds) + { + var item = _libraryManager.GetItemById(id); + + await _libraryManager.DeleteItem(item, new DeleteOptions + { + DeleteFileLocation = false + + }).ConfigureAwait(false); + } + progress.Report(100); } } diff --git a/MediaBrowser.Server.Implementations/Library/Validators/GenresValidator.cs b/MediaBrowser.Server.Implementations/Library/Validators/GenresValidator.cs index fac5cfc35..6ab70ea22 100644 --- a/MediaBrowser.Server.Implementations/Library/Validators/GenresValidator.cs +++ b/MediaBrowser.Server.Implementations/Library/Validators/GenresValidator.cs @@ -1,4 +1,5 @@ -using MediaBrowser.Controller.Entities; +using System.Collections.Generic; +using MediaBrowser.Controller.Entities; using MediaBrowser.Controller.Entities.Audio; using MediaBrowser.Controller.Library; using MediaBrowser.Model.Logging; @@ -43,12 +44,16 @@ namespace MediaBrowser.Server.Implementations.Library.Validators var numComplete = 0; var count = items.Count; + var validIds = new List<Guid>(); + foreach (var name in items) { try { var itemByName = _libraryManager.GetGenre(name); + validIds.Add(itemByName.Id); + await itemByName.RefreshMetadata(cancellationToken).ConfigureAwait(false); } catch (OperationCanceledException) @@ -69,6 +74,26 @@ namespace MediaBrowser.Server.Implementations.Library.Validators progress.Report(percent); } + var allIds = _libraryManager.GetItemIds(new InternalItemsQuery + { + IncludeItemTypes = new[] { typeof(Genre).Name } + }); + + var invalidIds = allIds + .Except(validIds) + .ToList(); + + foreach (var id in invalidIds) + { + var item = _libraryManager.GetItemById(id); + + await _libraryManager.DeleteItem(item, new DeleteOptions + { + DeleteFileLocation = false + + }).ConfigureAwait(false); + } + progress.Report(100); } } diff --git a/MediaBrowser.Server.Implementations/Library/Validators/MusicGenresValidator.cs b/MediaBrowser.Server.Implementations/Library/Validators/MusicGenresValidator.cs index e3be75e9b..8be0f4349 100644 --- a/MediaBrowser.Server.Implementations/Library/Validators/MusicGenresValidator.cs +++ b/MediaBrowser.Server.Implementations/Library/Validators/MusicGenresValidator.cs @@ -1,4 +1,6 @@ -using MediaBrowser.Controller.Entities.Audio; +using System.Collections.Generic; +using MediaBrowser.Controller.Entities; +using MediaBrowser.Controller.Entities.Audio; using MediaBrowser.Controller.Library; using MediaBrowser.Model.Logging; using System; @@ -42,12 +44,16 @@ namespace MediaBrowser.Server.Implementations.Library.Validators var numComplete = 0; var count = items.Count; + var validIds = new List<Guid>(); + foreach (var name in items) { try { var itemByName = _libraryManager.GetMusicGenre(name); + validIds.Add(itemByName.Id); + await itemByName.RefreshMetadata(cancellationToken).ConfigureAwait(false); } catch (OperationCanceledException) @@ -68,6 +74,26 @@ namespace MediaBrowser.Server.Implementations.Library.Validators progress.Report(percent); } + var allIds = _libraryManager.GetItemIds(new InternalItemsQuery + { + IncludeItemTypes = new[] { typeof(MusicGenre).Name } + }); + + var invalidIds = allIds + .Except(validIds) + .ToList(); + + foreach (var id in invalidIds) + { + var item = _libraryManager.GetItemById(id); + + await _libraryManager.DeleteItem(item, new DeleteOptions + { + DeleteFileLocation = false + + }).ConfigureAwait(false); + } + progress.Report(100); } } diff --git a/MediaBrowser.Server.Implementations/Library/Validators/StudiosValidator.cs b/MediaBrowser.Server.Implementations/Library/Validators/StudiosValidator.cs index 066b96853..c90cbb2f0 100644 --- a/MediaBrowser.Server.Implementations/Library/Validators/StudiosValidator.cs +++ b/MediaBrowser.Server.Implementations/Library/Validators/StudiosValidator.cs @@ -1,6 +1,8 @@ -using MediaBrowser.Controller.Library; +using MediaBrowser.Controller.Entities; +using MediaBrowser.Controller.Library; using MediaBrowser.Model.Logging; using System; +using System.Collections.Generic; using System.Linq; using System.Threading; using System.Threading.Tasks; @@ -41,12 +43,16 @@ namespace MediaBrowser.Server.Implementations.Library.Validators var numComplete = 0; var count = items.Count; + var validIds = new List<Guid>(); + foreach (var name in items) { try { var itemByName = _libraryManager.GetStudio(name); + validIds.Add(itemByName.Id); + await itemByName.RefreshMetadata(cancellationToken).ConfigureAwait(false); } catch (OperationCanceledException) @@ -67,6 +73,26 @@ namespace MediaBrowser.Server.Implementations.Library.Validators progress.Report(percent); } + var allIds = _libraryManager.GetItemIds(new InternalItemsQuery + { + IncludeItemTypes = new[] { typeof(Studio).Name } + }); + + var invalidIds = allIds + .Except(validIds) + .ToList(); + + foreach (var id in invalidIds) + { + var item = _libraryManager.GetItemById(id); + + await _libraryManager.DeleteItem(item, new DeleteOptions + { + DeleteFileLocation = false + + }).ConfigureAwait(false); + } + progress.Report(100); } } diff --git a/MediaBrowser.Server.Implementations/LiveTv/EmbyTV/EmbyTV.cs b/MediaBrowser.Server.Implementations/LiveTv/EmbyTV/EmbyTV.cs index 708828d47..3c65ac739 100644 --- a/MediaBrowser.Server.Implementations/LiveTv/EmbyTV/EmbyTV.cs +++ b/MediaBrowser.Server.Implementations/LiveTv/EmbyTV/EmbyTV.cs @@ -627,31 +627,17 @@ namespace MediaBrowser.Server.Implementations.LiveTv.EmbyTV private async Task UpdateTimersForSeriesTimer(List<ProgramInfo> epgData, SeriesTimerInfo seriesTimer) { - var newTimers = GetTimersForSeries(seriesTimer, epgData, _recordingProvider.GetAll()).ToList(); - - var existingTimers = _timerProvider.GetAll() - .Where(i => string.Equals(i.SeriesTimerId, seriesTimer.Id, StringComparison.OrdinalIgnoreCase)) - .ToList(); - var registration = await GetRegistrationInfo("seriesrecordings").ConfigureAwait(false); if (registration.IsValid) { + var newTimers = GetTimersForSeries(seriesTimer, epgData, _recordingProvider.GetAll()).ToList(); + foreach (var timer in newTimers) { _timerProvider.AddOrUpdate(timer); } } - - var newTimerIds = newTimers.Select(i => i.Id).ToList(); - - foreach (var timer in existingTimers) - { - if (!newTimerIds.Contains(timer.Id, StringComparer.OrdinalIgnoreCase)) - { - CancelTimerInternal(timer.Id); - } - } } private IEnumerable<TimerInfo> GetTimersForSeries(SeriesTimerInfo seriesTimer, IEnumerable<ProgramInfo> allPrograms, IReadOnlyList<RecordingInfo> currentRecordings) diff --git a/MediaBrowser.Server.Implementations/LiveTv/Listings/SchedulesDirect.cs b/MediaBrowser.Server.Implementations/LiveTv/Listings/SchedulesDirect.cs index 7a6860d65..129f922b3 100644 --- a/MediaBrowser.Server.Implementations/LiveTv/Listings/SchedulesDirect.cs +++ b/MediaBrowser.Server.Implementations/LiveTv/Listings/SchedulesDirect.cs @@ -304,7 +304,8 @@ namespace MediaBrowser.Server.Implementations.LiveTv.Listings IsKids = string.Equals(details.audience, "children", StringComparison.OrdinalIgnoreCase), IsSports = showType.IndexOf("sports", StringComparison.OrdinalIgnoreCase) != -1, IsMovie = showType.IndexOf("movie", StringComparison.OrdinalIgnoreCase) != -1 || showType.IndexOf("film", StringComparison.OrdinalIgnoreCase) != -1, - ShowId = programInfo.programID + ShowId = programInfo.programID, + Etag = programInfo.md5 }; if (programInfo.videoProperties != null) @@ -408,7 +409,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv.Listings ; }); imageIdString = imageIdString.TrimEnd(',') + "]"; - _logger.Debug("Json for show images = " + imageIdString); + var httpOptions = new HttpRequestOptions() { Url = ApiUrl + "/metadata/programs", diff --git a/MediaBrowser.Server.Implementations/LiveTv/LiveTvManager.cs b/MediaBrowser.Server.Implementations/LiveTv/LiveTvManager.cs index 4109617db..1721d6101 100644 --- a/MediaBrowser.Server.Implementations/LiveTv/LiveTvManager.cs +++ b/MediaBrowser.Server.Implementations/LiveTv/LiveTvManager.cs @@ -593,7 +593,8 @@ namespace MediaBrowser.Server.Implementations.LiveTv Name = info.Name, Id = id, DateCreated = DateTime.UtcNow, - DateModified = DateTime.UtcNow + DateModified = DateTime.UtcNow, + Etag = info.Etag }; } @@ -639,7 +640,11 @@ namespace MediaBrowser.Server.Implementations.LiveTv } else { - await _libraryManager.UpdateItem(item, ItemUpdateType.MetadataImport, cancellationToken).ConfigureAwait(false); + if (string.IsNullOrWhiteSpace(info.Etag) || !string.Equals(info.Etag, item.Etag, StringComparison.OrdinalIgnoreCase)) + { + item.Etag = info.Etag; + await _libraryManager.UpdateItem(item, ItemUpdateType.MetadataImport, cancellationToken).ConfigureAwait(false); + } } _providerManager.QueueRefresh(item.Id, new MetadataRefreshOptions()); diff --git a/MediaBrowser.WebDashboard/Api/PackageCreator.cs b/MediaBrowser.WebDashboard/Api/PackageCreator.cs index 104d02bcf..463c8829c 100644 --- a/MediaBrowser.WebDashboard/Api/PackageCreator.cs +++ b/MediaBrowser.WebDashboard/Api/PackageCreator.cs @@ -61,7 +61,7 @@ namespace MediaBrowser.WebDashboard.Api // jQuery ajax doesn't seem to handle if-modified-since correctly if (IsFormat(path, "html")) { - if (IsCoreHtml(path)) + if (IsCoreHtml(path) && path.IndexOf(".template.html", StringComparison.OrdinalIgnoreCase) == -1) { resourceStream = await ModifyHtml(resourceStream, mode, appVersion, localizationCulture, enableMinification).ConfigureAwait(false); } diff --git a/MediaBrowser.WebDashboard/MediaBrowser.WebDashboard.csproj b/MediaBrowser.WebDashboard/MediaBrowser.WebDashboard.csproj index e256cdb7c..4820535d0 100644 --- a/MediaBrowser.WebDashboard/MediaBrowser.WebDashboard.csproj +++ b/MediaBrowser.WebDashboard/MediaBrowser.WebDashboard.csproj @@ -186,9 +186,6 @@ <Content Include="dashboard-ui\css\nowplayingbar.css"> <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory> </Content> - <Content Include="dashboard-ui\livetvguideprovider-scd.html"> - <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory> - </Content> <Content Include="dashboard-ui\livetvguideprovider.html"> <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory> </Content> @@ -222,9 +219,6 @@ <Content Include="dashboard-ui\scripts\homeupcoming.js"> <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory> </Content> - <Content Include="dashboard-ui\scripts\livetvguideprovider-scd.js"> - <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory> - </Content> <Content Include="dashboard-ui\scripts\livetvguideprovider.js"> <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory> </Content> @@ -264,6 +258,9 @@ <Content Include="dashboard-ui\scripts\slideshow.js"> <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory> </Content> + <Content Include="dashboard-ui\scripts\wizardlivetvguide.js"> + <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory> + </Content> <Content Include="dashboard-ui\scripts\wizardlivetvtuner.js"> <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory> </Content> @@ -377,6 +374,12 @@ <Content Include="dashboard-ui\thirdparty\viblast\worker.html"> <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory> </Content> + <Content Include="dashboard-ui\tvproviders\schedulesdirect.js"> + <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory> + </Content> + <Content Include="dashboard-ui\tvproviders\schedulesdirect.template.html"> + <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory> + </Content> <Content Include="dashboard-ui\voice\voice.css"> <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory> </Content> @@ -1786,6 +1789,9 @@ <Content Include="dashboard-ui\wizardagreement.html"> <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory> </Content> + <Content Include="dashboard-ui\wizardlivetvguide.html"> + <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory> + </Content> <Content Include="dashboard-ui\wizardlivetvtuner.html"> <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory> </Content> -- cgit v1.2.3 From 8e8ce40de20c2d85e09a33c8345b7dbac0a6419d Mon Sep 17 00:00:00 2001 From: Luke Pulverenti <luke.pulverenti@gmail.com> Date: Mon, 31 Aug 2015 00:57:12 -0400 Subject: display current program in tv channel osd --- MediaBrowser.Controller/LiveTv/ILiveTvManager.cs | 9 +++++++ MediaBrowser.Model/Dto/BaseItemDto.cs | 6 ++++- .../Dto/DtoService.cs | 16 ++++++------- .../LiveTv/LiveTvManager.cs | 28 ++++++++++++++++++++++ 4 files changed, 50 insertions(+), 9 deletions(-) (limited to 'MediaBrowser.Controller/LiveTv') diff --git a/MediaBrowser.Controller/LiveTv/ILiveTvManager.cs b/MediaBrowser.Controller/LiveTv/ILiveTvManager.cs index 2b121eeeb..1458c1bc2 100644 --- a/MediaBrowser.Controller/LiveTv/ILiveTvManager.cs +++ b/MediaBrowser.Controller/LiveTv/ILiveTvManager.cs @@ -372,5 +372,14 @@ namespace MediaBrowser.Controller.LiveTv /// <param name="feature">The feature.</param> /// <returns>Task<MBRegistrationRecord>.</returns> Task<MBRegistrationRecord> GetRegistrationInfo(string channelId, string programId, string feature); + + /// <summary> + /// Adds the channel information. + /// </summary> + /// <param name="dto">The dto.</param> + /// <param name="channel">The channel.</param> + /// <param name="options">The options.</param> + /// <param name="user">The user.</param> + void AddChannelInfo(BaseItemDto dto, LiveTvChannel channel, DtoOptions options, User user); } } diff --git a/MediaBrowser.Model/Dto/BaseItemDto.cs b/MediaBrowser.Model/Dto/BaseItemDto.cs index ac8fa3370..a1c075563 100644 --- a/MediaBrowser.Model/Dto/BaseItemDto.cs +++ b/MediaBrowser.Model/Dto/BaseItemDto.cs @@ -1195,6 +1195,10 @@ namespace MediaBrowser.Model.Dto /// </summary> /// <value>The timer identifier.</value> public string TimerId { get; set; } - + /// <summary> + /// Gets or sets the current program. + /// </summary> + /// <value>The current program.</value> + public BaseItemDto CurrentProgram { get; set; } } } diff --git a/MediaBrowser.Server.Implementations/Dto/DtoService.cs b/MediaBrowser.Server.Implementations/Dto/DtoService.cs index aa6ab1d65..edfef38fd 100644 --- a/MediaBrowser.Server.Implementations/Dto/DtoService.cs +++ b/MediaBrowser.Server.Implementations/Dto/DtoService.cs @@ -98,7 +98,7 @@ namespace MediaBrowser.Server.Implementations.Dto var byName = item as IItemByName; - if (byName != null && !(item is LiveTvChannel)) + if (byName != null) { if (options.Fields.Contains(ItemFields.ItemCounts)) { @@ -140,7 +140,7 @@ namespace MediaBrowser.Server.Implementations.Dto var byName = item as IItemByName; - if (byName != null && !(item is LiveTvChannel)) + if (byName != null) { if (options.Fields.Contains(ItemFields.ItemCounts)) { @@ -351,6 +351,12 @@ namespace MediaBrowser.Server.Implementations.Dto AttachBasicFields(dto, item, owner, options); + var tvChannel = item as LiveTvChannel; + if (tvChannel != null) + { + _livetvManager().AddChannelInfo(dto, tvChannel, options, user); + } + var collectionFolder = item as ICollectionFolder; if (collectionFolder != null) { @@ -1520,12 +1526,6 @@ namespace MediaBrowser.Server.Implementations.Dto SetPhotoProperties(dto, photo); } - var tvChannel = item as LiveTvChannel; - if (tvChannel != null) - { - dto.MediaSources = _mediaSourceManager().GetStaticMediaSources(tvChannel, true).ToList(); - } - dto.ChannelId = item.ChannelId; var channelItem = item as IChannelItem; diff --git a/MediaBrowser.Server.Implementations/LiveTv/LiveTvManager.cs b/MediaBrowser.Server.Implementations/LiveTv/LiveTvManager.cs index 9cd4a2334..ff7700124 100644 --- a/MediaBrowser.Server.Implementations/LiveTv/LiveTvManager.cs +++ b/MediaBrowser.Server.Implementations/LiveTv/LiveTvManager.cs @@ -1040,6 +1040,8 @@ namespace MediaBrowser.Server.Implementations.LiveTv { cancellationToken.ThrowIfCancellationRequested(); + _logger.Debug("Refreshing guide from {0}", service.Name); + try { var innerProgress = new ActionableProgress<double>(); @@ -1721,6 +1723,32 @@ namespace MediaBrowser.Server.Implementations.LiveTv return dto; } + public void AddChannelInfo(BaseItemDto dto, LiveTvChannel channel, DtoOptions options, User user) + { + dto.MediaSources = channel.GetMediaSources(true).ToList(); + + var now = DateTime.UtcNow; + + var programs = _libraryManager.GetItems(new InternalItemsQuery + { + IncludeItemTypes = new[] { typeof(LiveTvProgram).Name }, + ChannelIds = new[] { channel.Id.ToString("N") }, + MaxStartDate = now, + MinEndDate = now, + Limit = 1 + + }).Items.Cast<LiveTvProgram>(); + + var currentProgram = programs + .OrderBy(i => i.StartDate) + .FirstOrDefault(); + + if (currentProgram != null) + { + dto.CurrentProgram = _dtoService.GetBaseItemDto(currentProgram, options, user); + } + } + private async Task<Tuple<SeriesTimerInfo, ILiveTvService>> GetNewTimerDefaultsInternal(CancellationToken cancellationToken, LiveTvProgram program = null) { var service = program != null && !string.IsNullOrWhiteSpace(program.ServiceName) ? -- cgit v1.2.3