From c4ceeae8893ad12d4043fb40ba234c5b190029fb Mon Sep 17 00:00:00 2001 From: Luke Pulverenti Date: Sun, 3 Dec 2017 17:11:04 -0500 Subject: [PATCH 1/5] improve xmltv gz support --- .../Archiving/ZipClient.cs | 18 +++++ .../LiveTv/Listings/XmlTvListingsProvider.cs | 70 ++++++++++++++----- MediaBrowser.Model/IO/IZipClient.cs | 1 + 3 files changed, 72 insertions(+), 17 deletions(-) diff --git a/Emby.Server.Implementations/Archiving/ZipClient.cs b/Emby.Server.Implementations/Archiving/ZipClient.cs index d7d37bb61c..32938e151f 100644 --- a/Emby.Server.Implementations/Archiving/ZipClient.cs +++ b/Emby.Server.Implementations/Archiving/ZipClient.cs @@ -89,6 +89,24 @@ namespace Emby.Server.Implementations.Archiving } } + public void ExtractFirstFileFromGz(Stream source, string targetPath, string defaultFileName) + { + using (var reader = GZipReader.Open(source)) + { + if (reader.MoveToNextEntry()) + { + var entry = reader.Entry; + + var filename = entry.Key; + if (string.IsNullOrWhiteSpace(filename)) + { + filename = defaultFileName; + } + reader.WriteEntryToFile(Path.Combine(targetPath, filename)); + } + } + } + /// /// Extracts all from7z. /// diff --git a/Emby.Server.Implementations/LiveTv/Listings/XmlTvListingsProvider.cs b/Emby.Server.Implementations/LiveTv/Listings/XmlTvListingsProvider.cs index 95ec1dee0d..7c251e3039 100644 --- a/Emby.Server.Implementations/LiveTv/Listings/XmlTvListingsProvider.cs +++ b/Emby.Server.Implementations/LiveTv/Listings/XmlTvListingsProvider.cs @@ -105,31 +105,64 @@ namespace Emby.Server.Implementations.LiveTv.Listings if (string.Equals(ext, ".gz", StringComparison.OrdinalIgnoreCase)) { - using (var stream = _fileSystem.OpenRead(file)) + try { - var tempFolder = Path.Combine(_config.ApplicationPaths.TempDirectory, Guid.NewGuid().ToString()); - _fileSystem.CreateDirectory(tempFolder); + var tempFolder = ExtractGz(file); + return FindXmlFile(tempFolder); + } + catch (Exception ex) + { + //_logger.ErrorException("Error extracting from gz file {0}", ex, file); + } - try - { - _zipClient.ExtractAllFromGz(stream, tempFolder, true); - } - catch - { - // If the extraction fails just return the original file, it could be a gz - return file; - } - - return _fileSystem.GetFiles(tempFolder, true) - .Where(i => string.Equals(i.Extension, ".xml", StringComparison.OrdinalIgnoreCase)) - .Select(i => i.FullName) - .FirstOrDefault(); + try + { + var tempFolder = ExtractFirstFileFromGz(file); + return FindXmlFile(tempFolder); + } + catch (Exception ex) + { + //_logger.ErrorException("Error extracting from zip file {0}", ex, file); } } return file; } + private string ExtractFirstFileFromGz(string file) + { + using (var stream = _fileSystem.OpenRead(file)) + { + var tempFolder = Path.Combine(_config.ApplicationPaths.TempDirectory, Guid.NewGuid().ToString()); + _fileSystem.CreateDirectory(tempFolder); + + _zipClient.ExtractFirstFileFromGz(stream, tempFolder, "data.xml"); + + return tempFolder; + } + } + + private string ExtractGz(string file) + { + using (var stream = _fileSystem.OpenRead(file)) + { + var tempFolder = Path.Combine(_config.ApplicationPaths.TempDirectory, Guid.NewGuid().ToString()); + _fileSystem.CreateDirectory(tempFolder); + + _zipClient.ExtractAllFromGz(stream, tempFolder, true); + + return tempFolder; + } + } + + private string FindXmlFile(string directory) + { + return _fileSystem.GetFiles(directory, true) + .Where(i => string.Equals(i.Extension, ".xml", StringComparison.OrdinalIgnoreCase)) + .Select(i => i.FullName) + .FirstOrDefault(); + } + public async Task> GetProgramsAsync(ListingsProviderInfo info, string channelId, DateTime startDateUtc, DateTime endDateUtc, CancellationToken cancellationToken) { if (string.IsNullOrWhiteSpace(channelId)) @@ -149,6 +182,7 @@ namespace Emby.Server.Implementations.LiveTv.Listings _logger.Debug("Getting xmltv programs for channel {0}", channelId); var path = await GetXml(info.Path, cancellationToken).ConfigureAwait(false); + _logger.Debug("Opening XmlTvReader for {0}", path); var reader = new XmlTvReader(path, GetLanguage(info)); var results = reader.GetProgrammes(channelId, startDateUtc, endDateUtc, cancellationToken); @@ -251,6 +285,7 @@ namespace Emby.Server.Implementations.LiveTv.Listings { // In theory this should never be called because there is always only one lineup var path = await GetXml(info.Path, CancellationToken.None).ConfigureAwait(false); + _logger.Debug("Opening XmlTvReader for {0}", path); var reader = new XmlTvReader(path, GetLanguage(info)); var results = reader.GetChannels(); @@ -262,6 +297,7 @@ namespace Emby.Server.Implementations.LiveTv.Listings { // In theory this should never be called because there is always only one lineup var path = await GetXml(info.Path, cancellationToken).ConfigureAwait(false); + _logger.Debug("Opening XmlTvReader for {0}", path); var reader = new XmlTvReader(path, GetLanguage(info)); var results = reader.GetChannels(); diff --git a/MediaBrowser.Model/IO/IZipClient.cs b/MediaBrowser.Model/IO/IZipClient.cs index 2dc4880c2f..4ebcba9d89 100644 --- a/MediaBrowser.Model/IO/IZipClient.cs +++ b/MediaBrowser.Model/IO/IZipClient.cs @@ -24,6 +24,7 @@ namespace MediaBrowser.Model.IO void ExtractAll(Stream source, string targetPath, bool overwriteExistingFiles); void ExtractAllFromGz(Stream source, string targetPath, bool overwriteExistingFiles); + void ExtractFirstFileFromGz(Stream source, string targetPath, string defaultFileName); /// /// Extracts all from zip. From 70b0dd968fc381faacbf2207e3a5364d793bd98e Mon Sep 17 00:00:00 2001 From: Luke Pulverenti Date: Sun, 3 Dec 2017 17:12:46 -0500 Subject: [PATCH 2/5] Improve support for embedded metadata; support external subtitles with strm files --- .../LiveTv/TunerHosts/BaseTunerHost.cs | 8 + .../MediaEncoder/EncodingManager.cs | 25 ++-- MediaBrowser.Controller/LiveTv/ITunerHost.cs | 4 + .../MediaInfo/FFProbeProvider.cs | 1 - .../MediaInfo/FFProbeVideoInfo.cs | 141 ++++++++++-------- .../Movies/GenericMovieDbInfo.cs | 2 +- 6 files changed, 108 insertions(+), 73 deletions(-) diff --git a/Emby.Server.Implementations/LiveTv/TunerHosts/BaseTunerHost.cs b/Emby.Server.Implementations/LiveTv/TunerHosts/BaseTunerHost.cs index e0fd32aeef..45e96c36d8 100644 --- a/Emby.Server.Implementations/LiveTv/TunerHosts/BaseTunerHost.cs +++ b/Emby.Server.Implementations/LiveTv/TunerHosts/BaseTunerHost.cs @@ -39,6 +39,14 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts FileSystem = fileSystem; } + public virtual bool IsSupported + { + get + { + return true; + } + } + protected abstract Task> GetChannelsInternal(TunerHostInfo tuner, CancellationToken cancellationToken); public abstract string Type { get; } diff --git a/Emby.Server.Implementations/MediaEncoder/EncodingManager.cs b/Emby.Server.Implementations/MediaEncoder/EncodingManager.cs index 6e0e55bef4..d790f4ab8b 100644 --- a/Emby.Server.Implementations/MediaEncoder/EncodingManager.cs +++ b/Emby.Server.Implementations/MediaEncoder/EncodingManager.cs @@ -76,6 +76,21 @@ namespace Emby.Server.Implementations.MediaEncoder return false; } + if (video.VideoType == VideoType.Iso) + { + return false; + } + + if (video.VideoType == VideoType.BluRay || video.VideoType == VideoType.Dvd) + { + return false; + } + + if (video.IsShortcut) + { + return false; + } + if (!video.IsCompleteMedia) { return false; @@ -118,16 +133,6 @@ namespace Emby.Server.Implementations.MediaEncoder { if (extractImages) { - if (video.VideoType == VideoType.Iso) - { - continue; - } - - if (video.VideoType == VideoType.BluRay || video.VideoType == VideoType.Dvd) - { - continue; - } - try { // Add some time for the first chapter to make sure we don't end up with a black image diff --git a/MediaBrowser.Controller/LiveTv/ITunerHost.cs b/MediaBrowser.Controller/LiveTv/ITunerHost.cs index 242011db06..80c40f8bde 100644 --- a/MediaBrowser.Controller/LiveTv/ITunerHost.cs +++ b/MediaBrowser.Controller/LiveTv/ITunerHost.cs @@ -46,6 +46,10 @@ namespace MediaBrowser.Controller.LiveTv Task> GetChannelStreamMediaSources(string channelId, CancellationToken cancellationToken); Task> DiscoverDevices(int discoveryDurationMs, CancellationToken cancellationToken); + bool IsSupported + { + get; + } } public interface IConfigurableTunerHost { diff --git a/MediaBrowser.Providers/MediaInfo/FFProbeProvider.cs b/MediaBrowser.Providers/MediaInfo/FFProbeProvider.cs index e79aec33c1..6a2677b433 100644 --- a/MediaBrowser.Providers/MediaInfo/FFProbeProvider.cs +++ b/MediaBrowser.Providers/MediaInfo/FFProbeProvider.cs @@ -153,7 +153,6 @@ namespace MediaBrowser.Providers.MediaInfo if (item.IsShortcut) { FetchShortcutInfo(item); - return Task.FromResult(ItemUpdateType.MetadataImport); } var prober = new FFProbeVideoInfo(_logger, _isoManager, _mediaEncoder, _itemRepo, _blurayExaminer, _localization, _appPaths, _json, _encodingManager, _fileSystem, _config, _subtitleManager, _chapterManager, _libraryManager); diff --git a/MediaBrowser.Providers/MediaInfo/FFProbeVideoInfo.cs b/MediaBrowser.Providers/MediaInfo/FFProbeVideoInfo.cs index 1582385571..443eb6eda4 100644 --- a/MediaBrowser.Providers/MediaInfo/FFProbeVideoInfo.cs +++ b/MediaBrowser.Providers/MediaInfo/FFProbeVideoInfo.cs @@ -75,49 +75,54 @@ namespace MediaBrowser.Providers.MediaInfo try { - string[] streamFileNames = null; + Model.MediaInfo.MediaInfo mediaInfoResult = null; - if (item.VideoType == VideoType.Iso) + if (!item.IsShortcut) { - item.IsoType = DetermineIsoType(isoMount); - } + string[] streamFileNames = null; - if (item.VideoType == VideoType.Dvd || (item.IsoType.HasValue && item.IsoType == IsoType.Dvd)) - { - streamFileNames = FetchFromDvdLib(item, isoMount); - - if (streamFileNames.Length == 0) + if (item.VideoType == VideoType.Iso) { - _logger.Error("No playable vobs found in dvd structure, skipping ffprobe."); - return ItemUpdateType.MetadataImport; + item.IsoType = DetermineIsoType(isoMount); } - } - else if (item.VideoType == VideoType.BluRay || (item.IsoType.HasValue && item.IsoType == IsoType.BluRay)) - { - var inputPath = isoMount != null ? isoMount.MountedPath : item.Path; - - blurayDiscInfo = GetBDInfo(inputPath); - - streamFileNames = blurayDiscInfo.Files; - - if (streamFileNames.Length == 0) + if (item.VideoType == VideoType.Dvd || (item.IsoType.HasValue && item.IsoType == IsoType.Dvd)) { - _logger.Error("No playable vobs found in bluray structure, skipping ffprobe."); - return ItemUpdateType.MetadataImport; + streamFileNames = FetchFromDvdLib(item, isoMount); + + if (streamFileNames.Length == 0) + { + _logger.Error("No playable vobs found in dvd structure, skipping ffprobe."); + return ItemUpdateType.MetadataImport; + } } + + else if (item.VideoType == VideoType.BluRay || (item.IsoType.HasValue && item.IsoType == IsoType.BluRay)) + { + var inputPath = isoMount != null ? isoMount.MountedPath : item.Path; + + blurayDiscInfo = GetBDInfo(inputPath); + + streamFileNames = blurayDiscInfo.Files; + + if (streamFileNames.Length == 0) + { + _logger.Error("No playable vobs found in bluray structure, skipping ffprobe."); + return ItemUpdateType.MetadataImport; + } + } + + if (streamFileNames == null) + { + streamFileNames = new string[] { }; + } + + mediaInfoResult = await GetMediaInfo(item, isoMount, streamFileNames, cancellationToken).ConfigureAwait(false); + + cancellationToken.ThrowIfCancellationRequested(); } - if (streamFileNames == null) - { - streamFileNames = new string[] { }; - } - - var result = await GetMediaInfo(item, isoMount, streamFileNames, cancellationToken).ConfigureAwait(false); - - cancellationToken.ThrowIfCancellationRequested(); - - await Fetch(item, cancellationToken, result, isoMount, blurayDiscInfo, options).ConfigureAwait(false); + await Fetch(item, cancellationToken, mediaInfoResult, isoMount, blurayDiscInfo, options).ConfigureAwait(false); } finally @@ -162,43 +167,60 @@ namespace MediaBrowser.Providers.MediaInfo BlurayDiscInfo blurayInfo, MetadataRefreshOptions options) { - var mediaStreams = mediaInfo.MediaStreams; + List mediaStreams; + List chapters; - video.TotalBitrate = mediaInfo.Bitrate; - //video.FormatName = (mediaInfo.Container ?? string.Empty) - // .Replace("matroska", "mkv", StringComparison.OrdinalIgnoreCase); - - // For dvd's this may not always be accurate, so don't set the runtime if the item already has one - var needToSetRuntime = video.VideoType != VideoType.Dvd || video.RunTimeTicks == null || video.RunTimeTicks.Value == 0; - - if (needToSetRuntime) + if (mediaInfo != null) { - video.RunTimeTicks = mediaInfo.RunTimeTicks; - } + mediaStreams = mediaInfo.MediaStreams; - if (video.VideoType == VideoType.VideoFile) - { - var extension = (Path.GetExtension(video.Path) ?? string.Empty).TrimStart('.'); + video.TotalBitrate = mediaInfo.Bitrate; + //video.FormatName = (mediaInfo.Container ?? string.Empty) + // .Replace("matroska", "mkv", StringComparison.OrdinalIgnoreCase); - video.Container = extension; + // For dvd's this may not always be accurate, so don't set the runtime if the item already has one + var needToSetRuntime = video.VideoType != VideoType.Dvd || video.RunTimeTicks == null || video.RunTimeTicks.Value == 0; + + if (needToSetRuntime) + { + video.RunTimeTicks = mediaInfo.RunTimeTicks; + } + + if (video.VideoType == VideoType.VideoFile) + { + var extension = (Path.GetExtension(video.Path) ?? string.Empty).TrimStart('.'); + + video.Container = extension; + } + else + { + video.Container = null; + } + video.Container = mediaInfo.Container; + + chapters = mediaInfo.Chapters == null ? new List() : mediaInfo.Chapters.ToList(); + if (blurayInfo != null) + { + FetchBdInfo(video, chapters, mediaStreams, blurayInfo); + } } else { - video.Container = null; - } - video.Container = mediaInfo.Container; - - var chapters = mediaInfo.Chapters == null ? new List() : mediaInfo.Chapters.ToList(); - if (blurayInfo != null) - { - FetchBdInfo(video, chapters, mediaStreams, blurayInfo); + mediaStreams = new List(); + chapters = new List(); } await AddExternalSubtitles(video, mediaStreams, options, cancellationToken).ConfigureAwait(false); + var libraryOptions = _libraryManager.GetLibraryOptions(video); - FetchEmbeddedInfo(video, mediaInfo, options, libraryOptions); - FetchPeople(video, mediaInfo, options); + if (mediaInfo != null) + { + FetchEmbeddedInfo(video, mediaInfo, options, libraryOptions); + FetchPeople(video, mediaInfo, options); + video.Timestamp = mediaInfo.Timestamp; + video.Video3DFormat = video.Video3DFormat ?? mediaInfo.Video3DFormat; + } video.IsHD = mediaStreams.Any(i => i.Type == MediaStreamType.Video && i.Width.HasValue && i.Width.Value >= 1260); @@ -207,9 +229,6 @@ namespace MediaBrowser.Providers.MediaInfo video.DefaultVideoStreamIndex = videoStream == null ? (int?)null : videoStream.Index; video.HasSubtitles = mediaStreams.Any(i => i.Type == MediaStreamType.Subtitle); - video.Timestamp = mediaInfo.Timestamp; - - video.Video3DFormat = video.Video3DFormat ?? mediaInfo.Video3DFormat; _itemRepo.SaveMediaStreams(video.Id, mediaStreams, cancellationToken); diff --git a/MediaBrowser.Providers/Movies/GenericMovieDbInfo.cs b/MediaBrowser.Providers/Movies/GenericMovieDbInfo.cs index 65742f6e6e..a000ed36e4 100644 --- a/MediaBrowser.Providers/Movies/GenericMovieDbInfo.cs +++ b/MediaBrowser.Providers/Movies/GenericMovieDbInfo.cs @@ -262,7 +262,7 @@ namespace MediaBrowser.Providers.Movies var keepTypes = new[] { PersonType.Director, - PersonType.Writer, + //PersonType.Writer, //PersonType.Producer }; From 8717f81bf406fb4f78adf117fd380f37bd6a98fc Mon Sep 17 00:00:00 2001 From: Luke Pulverenti Date: Sun, 3 Dec 2017 17:14:35 -0500 Subject: [PATCH 3/5] Add setting to auto-run web app when server starts --- .../ApplicationHost.cs | 37 +++++++++++++++---- .../EntryPoints/StartupWizard.cs | 9 ++++- MediaBrowser.Api/StartupWizardService.cs | 1 + .../IServerApplicationHost.cs | 4 +- .../Configuration/ServerConfiguration.cs | 2 + MediaBrowser.Model/System/SystemInfo.cs | 2 + 6 files changed, 45 insertions(+), 10 deletions(-) diff --git a/Emby.Server.Implementations/ApplicationHost.cs b/Emby.Server.Implementations/ApplicationHost.cs index abc6c35666..26450c06ca 100644 --- a/Emby.Server.Implementations/ApplicationHost.cs +++ b/Emby.Server.Implementations/ApplicationHost.cs @@ -148,6 +148,34 @@ namespace Emby.Server.Implementations } } + public virtual bool CanLaunchWebBrowser + { + get + { + if (!Environment.UserInteractive) + { + return false; + } + + if (StartupOptions.ContainsOption("-service")) + { + return false; + } + + if (EnvironmentInfo.OperatingSystem == MediaBrowser.Model.System.OperatingSystem.Windows) + { + return true; + } + + if (EnvironmentInfo.OperatingSystem == MediaBrowser.Model.System.OperatingSystem.OSX) + { + return true; + } + + return false; + } + } + /// /// Occurs when [has pending restart changed]. /// @@ -1936,6 +1964,7 @@ namespace Emby.Server.Implementations OperatingSystemDisplayName = OperatingSystemDisplayName, CanSelfRestart = CanSelfRestart, CanSelfUpdate = CanSelfUpdate, + CanLaunchWebBrowser = CanLaunchWebBrowser, WanAddress = ConnectManager.WanApiAddress, HasUpdateAvailable = HasUpdateAvailable, SupportsAutoRunAtStartup = SupportsAutoRunAtStartup, @@ -2358,13 +2387,7 @@ namespace Emby.Server.Implementations public virtual void LaunchUrl(string url) { - if (EnvironmentInfo.OperatingSystem != MediaBrowser.Model.System.OperatingSystem.Windows && - EnvironmentInfo.OperatingSystem != MediaBrowser.Model.System.OperatingSystem.OSX) - { - throw new NotSupportedException(); - } - - if (!Environment.UserInteractive) + if (!CanLaunchWebBrowser) { throw new NotSupportedException(); } diff --git a/Emby.Server.Implementations/EntryPoints/StartupWizard.cs b/Emby.Server.Implementations/EntryPoints/StartupWizard.cs index 746edf9e7b..103b4b321e 100644 --- a/Emby.Server.Implementations/EntryPoints/StartupWizard.cs +++ b/Emby.Server.Implementations/EntryPoints/StartupWizard.cs @@ -35,15 +35,20 @@ namespace Emby.Server.Implementations.EntryPoints /// public void Run() { + if (!_appHost.CanLaunchWebBrowser) + { + return; + } + if (_appHost.IsFirstRun) { BrowserLauncher.OpenDashboardPage("wizardstart.html", _appHost); } - else if (_config.Configuration.IsStartupWizardCompleted) + else if (_config.Configuration.IsStartupWizardCompleted && _config.Configuration.AutoRunWebApp) { var options = ((ApplicationHost)_appHost).StartupOptions; - if (!options.ContainsOption("-service") && !options.ContainsOption("-nobrowser")) + if (!options.ContainsOption("-noautorunwebapp")) { BrowserLauncher.OpenDashboardPage("index.html", _appHost); } diff --git a/MediaBrowser.Api/StartupWizardService.cs b/MediaBrowser.Api/StartupWizardService.cs index 54e4657c11..c6345c17f4 100644 --- a/MediaBrowser.Api/StartupWizardService.cs +++ b/MediaBrowser.Api/StartupWizardService.cs @@ -67,6 +67,7 @@ namespace MediaBrowser.Api public void Post(ReportStartupWizardComplete request) { _config.Configuration.IsStartupWizardCompleted = true; + _config.Configuration.AutoRunWebApp = true; _config.SetOptimalValues(); _config.SaveConfiguration(); diff --git a/MediaBrowser.Controller/IServerApplicationHost.cs b/MediaBrowser.Controller/IServerApplicationHost.cs index 89ae85b508..3f7f8248b5 100644 --- a/MediaBrowser.Controller/IServerApplicationHost.cs +++ b/MediaBrowser.Controller/IServerApplicationHost.cs @@ -29,7 +29,9 @@ namespace MediaBrowser.Controller /// /// true if [supports automatic run at startup]; otherwise, false. bool SupportsAutoRunAtStartup { get; } - + + bool CanLaunchWebBrowser { get; } + /// /// Gets the HTTP server port. /// diff --git a/MediaBrowser.Model/Configuration/ServerConfiguration.cs b/MediaBrowser.Model/Configuration/ServerConfiguration.cs index f2c3b7cc8a..41ed0648a6 100644 --- a/MediaBrowser.Model/Configuration/ServerConfiguration.cs +++ b/MediaBrowser.Model/Configuration/ServerConfiguration.cs @@ -61,6 +61,8 @@ namespace MediaBrowser.Model.Configuration /// true if this instance is port authorized; otherwise, false. public bool IsPortAuthorized { get; set; } + public bool AutoRunWebApp { get; set; } + /// /// Gets or sets a value indicating whether [enable case sensitive item ids]. /// diff --git a/MediaBrowser.Model/System/SystemInfo.cs b/MediaBrowser.Model/System/SystemInfo.cs index b61d637293..9ed0f904f0 100644 --- a/MediaBrowser.Model/System/SystemInfo.cs +++ b/MediaBrowser.Model/System/SystemInfo.cs @@ -68,6 +68,8 @@ namespace MediaBrowser.Model.System /// true if this instance can self update; otherwise, false. public bool CanSelfUpdate { get; set; } + public bool CanLaunchWebBrowser { get; set; } + /// /// Gets or sets plugin assemblies that failed to load. /// From 175c085d90316b5ec978313c46ab96f779465304 Mon Sep 17 00:00:00 2001 From: Luke Pulverenti Date: Sun, 3 Dec 2017 17:15:21 -0500 Subject: [PATCH 4/5] Stub out new filtering api --- .../Data/SqliteItemRepository.cs | 8 +- .../LiveTv/LiveTvManager.cs | 3 +- MediaBrowser.Api/FilterService.cs | 126 +++++++++++++++++- MediaBrowser.Api/LiveTv/LiveTvService.cs | 4 + MediaBrowser.Model/LiveTv/ProgramQuery.cs | 2 + MediaBrowser.Model/Querying/QueryFilters.cs | 18 ++- 6 files changed, 151 insertions(+), 10 deletions(-) diff --git a/Emby.Server.Implementations/Data/SqliteItemRepository.cs b/Emby.Server.Implementations/Data/SqliteItemRepository.cs index ddead897eb..830d6447ec 100644 --- a/Emby.Server.Implementations/Data/SqliteItemRepository.cs +++ b/Emby.Server.Implementations/Data/SqliteItemRepository.cs @@ -5264,7 +5264,13 @@ where AncestorIdText not null and ItemValues.Value not null and ItemValues.Type ItemIds = query.ItemIds, TopParentIds = query.TopParentIds, ParentId = query.ParentId, - IsPlayed = query.IsPlayed + IsPlayed = query.IsPlayed, + IsAiring = query.IsAiring, + IsMovie = query.IsMovie, + IsSports = query.IsSports, + IsKids = query.IsKids, + IsNews = query.IsNews, + IsSeries = query.IsSeries }; var innerWhereClauses = GetWhereClauses(innerQuery, null); diff --git a/Emby.Server.Implementations/LiveTv/LiveTvManager.cs b/Emby.Server.Implementations/LiveTv/LiveTvManager.cs index 7e27877e7c..66eabf523a 100644 --- a/Emby.Server.Implementations/LiveTv/LiveTvManager.cs +++ b/Emby.Server.Implementations/LiveTv/LiveTvManager.cs @@ -125,7 +125,7 @@ namespace Emby.Server.Implementations.LiveTv public void AddParts(IEnumerable services, IEnumerable tunerHosts, IEnumerable listingProviders) { _services = services.ToArray(); - _tunerHosts.AddRange(tunerHosts); + _tunerHosts.AddRange(tunerHosts.Where(i => i.IsSupported)); _listingProviders.AddRange(listingProviders); foreach (var service in _services) @@ -947,6 +947,7 @@ namespace Emby.Server.Implementations.LiveTv IsKids = query.IsKids, IsNews = query.IsNews, Genres = query.Genres, + GenreIds = query.GenreIds, StartIndex = query.StartIndex, Limit = query.Limit, OrderBy = query.OrderBy, diff --git a/MediaBrowser.Api/FilterService.cs b/MediaBrowser.Api/FilterService.cs index 52b274653b..585e9c49bc 100644 --- a/MediaBrowser.Api/FilterService.cs +++ b/MediaBrowser.Api/FilterService.cs @@ -2,6 +2,7 @@ using MediaBrowser.Controller.Library; using MediaBrowser.Controller.Net; using MediaBrowser.Model.Querying; +using MediaBrowser.Model.Dto; using System; using System.Collections.Generic; using System.Linq; @@ -11,7 +12,7 @@ using MediaBrowser.Model.Services; namespace MediaBrowser.Api { [Route("/Items/Filters", "GET", Summary = "Gets branding configuration")] - public class GetQueryFilters : IReturn + public class GetQueryFiltersLegacy : IReturn { /// /// Gets or sets the user id. @@ -40,6 +41,43 @@ namespace MediaBrowser.Api } } + [Route("/Items/Filters2", "GET", Summary = "Gets branding configuration")] + public class GetQueryFilters : IReturn + { + /// + /// Gets or sets the user id. + /// + /// The user id. + [ApiMember(Name = "UserId", Description = "User Id", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET")] + public string UserId { get; set; } + + [ApiMember(Name = "ParentId", Description = "Specify this to localize the search to a specific item or folder. Omit to use the root", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET")] + public string ParentId { get; set; } + + [ApiMember(Name = "IncludeItemTypes", Description = "Optional. If specified, results will be filtered based on item type. This allows multiple, comma delimeted.", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET", AllowMultiple = true)] + public string IncludeItemTypes { get; set; } + + [ApiMember(Name = "MediaTypes", Description = "Optional filter by MediaType. Allows multiple, comma delimited.", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET", AllowMultiple = true)] + public string MediaTypes { get; set; } + + public string[] GetMediaTypes() + { + return (MediaTypes ?? string.Empty).Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries); + } + + public string[] GetIncludeItemTypes() + { + return (IncludeItemTypes ?? string.Empty).Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries); + } + + public bool? IsAiring { get; set; } + public bool? IsMovie { get; set; } + public bool? IsSports { get; set; } + public bool? IsKids { get; set; } + public bool? IsNews { get; set; } + public bool? IsSeries { get; set; } + } + [Authenticated] public class FilterService : BaseApiService { @@ -57,18 +95,96 @@ namespace MediaBrowser.Api var parentItem = string.IsNullOrEmpty(request.ParentId) ? null : _libraryManager.GetItemById(request.ParentId); var user = !string.IsNullOrWhiteSpace(request.UserId) ? _userManager.GetUserById(request.UserId) : null; + if (string.Equals(request.IncludeItemTypes, "BoxSet", StringComparison.OrdinalIgnoreCase) || + string.Equals(request.IncludeItemTypes, "Playlist", StringComparison.OrdinalIgnoreCase) || + string.Equals(request.IncludeItemTypes, typeof(Trailer).Name, StringComparison.OrdinalIgnoreCase) || + string.Equals(request.IncludeItemTypes, "Program", StringComparison.OrdinalIgnoreCase)) + { + parentItem = null; + } + + var filters = new QueryFilters(); + + var genreQuery = new InternalItemsQuery(user) + { + AncestorIds = parentItem == null ? new string[] { } : new string[] { parentItem.Id.ToString("N") }, + IncludeItemTypes = request.GetIncludeItemTypes(), + DtoOptions = new Controller.Dto.DtoOptions + { + Fields = new ItemFields[] { }, + EnableImages = false, + EnableUserData = false + }, + IsAiring = request.IsAiring, + IsMovie = request.IsMovie, + IsSports = request.IsSports, + IsKids = request.IsKids, + IsNews = request.IsNews, + IsSeries = request.IsSeries + }; + + if (string.Equals(request.IncludeItemTypes, "MusicAlbum", StringComparison.OrdinalIgnoreCase) || + string.Equals(request.IncludeItemTypes, "MusicVideo", StringComparison.OrdinalIgnoreCase) || + string.Equals(request.IncludeItemTypes, "MusicArtist", StringComparison.OrdinalIgnoreCase) || + string.Equals(request.IncludeItemTypes, "Audio", StringComparison.OrdinalIgnoreCase)) + { + filters.Genres = _libraryManager.GetMusicGenres(genreQuery).Items.Select(i => new NameIdPair + { + Name = i.Item1.Name, + Id = i.Item1.Id.ToString("N") + + }).ToArray(); + } + else if (string.Equals(request.IncludeItemTypes, "Game", StringComparison.OrdinalIgnoreCase) || + string.Equals(request.IncludeItemTypes, "GameSystem", StringComparison.OrdinalIgnoreCase)) + { + filters.Genres = _libraryManager.GetGameGenres(genreQuery).Items.Select(i => new NameIdPair + { + Name = i.Item1.Name, + Id = i.Item1.Id.ToString("N") + + }).ToArray(); + } + else + { + filters.Genres = _libraryManager.GetGenres(genreQuery).Items.Select(i => new NameIdPair + { + Name = i.Item1.Name, + Id = i.Item1.Id.ToString("N") + + }).ToArray(); + } + + return ToOptimizedResult(filters); + } + + public object Get(GetQueryFiltersLegacy request) + { + var parentItem = string.IsNullOrEmpty(request.ParentId) ? null : _libraryManager.GetItemById(request.ParentId); + var user = !string.IsNullOrWhiteSpace(request.UserId) ? _userManager.GetUserById(request.UserId) : null; + + if (string.Equals(request.IncludeItemTypes, "BoxSet", StringComparison.OrdinalIgnoreCase) || + string.Equals(request.IncludeItemTypes, "Playlist", StringComparison.OrdinalIgnoreCase) || + string.Equals(request.IncludeItemTypes, typeof(Trailer).Name, StringComparison.OrdinalIgnoreCase) || + string.Equals(request.IncludeItemTypes, "Program", StringComparison.OrdinalIgnoreCase)) + { + parentItem = null; + } + var item = string.IsNullOrEmpty(request.ParentId) ? user == null ? _libraryManager.RootFolder : user.RootFolder : parentItem; var result = ((Folder)item).GetItemList(GetItemsQuery(request, user)); - return ToOptimizedResult(GetFilters(result)); + var filters = GetFilters(result); + + return ToOptimizedResult(filters); } - private QueryFilters GetFilters(BaseItem[] items) + private QueryFiltersLegacy GetFilters(BaseItem[] items) { - var result = new QueryFilters(); + var result = new QueryFiltersLegacy(); result.Years = items.Select(i => i.ProductionYear ?? -1) .Where(i => i > 0) @@ -97,7 +213,7 @@ namespace MediaBrowser.Api return result; } - private InternalItemsQuery GetItemsQuery(GetQueryFilters request, User user) + private InternalItemsQuery GetItemsQuery(GetQueryFiltersLegacy request, User user) { var query = new InternalItemsQuery { diff --git a/MediaBrowser.Api/LiveTv/LiveTvService.cs b/MediaBrowser.Api/LiveTv/LiveTvService.cs index 703c96e0c6..c137620481 100644 --- a/MediaBrowser.Api/LiveTv/LiveTvService.cs +++ b/MediaBrowser.Api/LiveTv/LiveTvService.cs @@ -379,6 +379,9 @@ 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 = "GenreIds", Description = "The genres to return guide information for.", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET,POST")] + public string GenreIds { 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; } @@ -1003,6 +1006,7 @@ namespace MediaBrowser.Api.LiveTv query.IsSports = request.IsSports; query.SeriesTimerId = request.SeriesTimerId; query.Genres = (request.Genres ?? String.Empty).Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries); + query.GenreIds = (request.GenreIds ?? String.Empty).Split(new[] { '|' }, StringSplitOptions.RemoveEmptyEntries); if (!string.IsNullOrWhiteSpace(request.LibrarySeriesId)) { diff --git a/MediaBrowser.Model/LiveTv/ProgramQuery.cs b/MediaBrowser.Model/LiveTv/ProgramQuery.cs index c0959635f3..ec3f8ad672 100644 --- a/MediaBrowser.Model/LiveTv/ProgramQuery.cs +++ b/MediaBrowser.Model/LiveTv/ProgramQuery.cs @@ -14,6 +14,7 @@ namespace MediaBrowser.Model.LiveTv ChannelIds = new string[] { }; OrderBy = new Tuple[] { }; Genres = new string[] { }; + GenreIds = new string[] { }; EnableTotalRecordCount = true; EnableUserData = true; } @@ -110,6 +111,7 @@ namespace MediaBrowser.Model.LiveTv /// Limit results to items containing specific genres /// /// The genres. + public string[] GenreIds { get; set; } public string[] Genres { get; set; } } } \ No newline at end of file diff --git a/MediaBrowser.Model/Querying/QueryFilters.cs b/MediaBrowser.Model/Querying/QueryFilters.cs index dd575c2a88..3a261857bd 100644 --- a/MediaBrowser.Model/Querying/QueryFilters.cs +++ b/MediaBrowser.Model/Querying/QueryFilters.cs @@ -1,14 +1,15 @@ - +using MediaBrowser.Model.Dto; + namespace MediaBrowser.Model.Querying { - public class QueryFilters + public class QueryFiltersLegacy { public string[] Genres { get; set; } public string[] Tags { get; set; } public string[] OfficialRatings { get; set; } public int[] Years { get; set; } - public QueryFilters() + public QueryFiltersLegacy() { Genres = new string[] { }; Tags = new string[] { }; @@ -16,4 +17,15 @@ namespace MediaBrowser.Model.Querying Years = new int[] { }; } } + public class QueryFilters + { + public NameIdPair[] Genres { get; set; } + public string[] Tags { get; set; } + + public QueryFilters() + { + Tags = new string[] { }; + Genres = new NameIdPair[] { }; + } + } } From 4ec4d38f49f6e6d64b7de190e44e9729291f6837 Mon Sep 17 00:00:00 2001 From: Luke Pulverenti Date: Sun, 3 Dec 2017 17:16:18 -0500 Subject: [PATCH 5/5] 3.2.40.7 --- SharedVersion.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/SharedVersion.cs b/SharedVersion.cs index f5f637be07..db8007e851 100644 --- a/SharedVersion.cs +++ b/SharedVersion.cs @@ -1,3 +1,3 @@ using System.Reflection; -[assembly: AssemblyVersion("3.2.40.6")] +[assembly: AssemblyVersion("3.2.40.7")]