From 1afb28b48797ee53442823cfd395e07d219e8ec3 Mon Sep 17 00:00:00 2001 From: Luke Pulverenti Date: Mon, 22 Sep 2014 17:56:54 -0400 Subject: [PATCH] add cinema mode feature --- MediaBrowser.Api/ApiEntryPoint.cs | 18 +- .../Playback/Hls/DynamicHlsService.cs | 2 +- .../Playback/Hls/HlsSegmentService.cs | 2 +- .../UserLibrary/UserLibraryService.cs | 4 +- .../Extensions/BaseExtensions.cs | 23 ++ .../Channels/ChannelVideoItem.cs | 12 +- .../Channels/IChannelManager.cs | 8 + .../Channels/IChannelMediaItem.cs | 2 - .../Entities/Audio/Audio.cs | 1 + MediaBrowser.Controller/Entities/BaseItem.cs | 121 +++++- .../Entities/Extensions.cs | 9 +- .../Entities/Movies/Movie.cs | 28 +- MediaBrowser.Controller/Entities/Video.cs | 1 + .../Library/IIntroProvider.cs | 9 +- .../Library/ILibraryManager.cs | 2 +- .../MediaBrowser.Controller.csproj | 1 + .../Providers/IExtrasProvider.cs | 39 ++ .../Providers/ItemLookupInfo.cs | 6 + .../Resolvers/EntityResolutionHelper.cs | 9 +- .../MediaBrowser.Model.Portable.csproj | 3 + .../MediaBrowser.Model.net35.csproj | 3 + .../Configuration/CinemaModeConfiguration.cs | 23 ++ .../Configuration/ServerConfiguration.cs | 5 +- .../Configuration/UserConfiguration.cs | 1 + MediaBrowser.Model/Entities/ExtraType.cs | 16 + MediaBrowser.Model/Entities/MediaUrl.cs | 1 - MediaBrowser.Model/MediaBrowser.Model.csproj | 2 + .../BoxSets/MovieDbBoxSetProvider.cs | 10 +- .../VideoChannelItemMetadataService.cs | 6 +- .../Manager/MetadataService.cs | 15 + .../Movies/FanartMovieImageProvider.cs | 3 +- .../Movies/GenericMovieDbInfo.cs | 1 - .../Movies/MovieDbImageProvider.cs | 9 + .../Movies/MovieDbProvider.cs | 8 +- .../Movies/MovieDbTrailerProvider.cs | 24 +- .../Movies/MovieExternalIds.cs | 18 +- .../Omdb/OmdbItemProvider.cs | 19 +- .../Channels/ChannelDownloadScheduledTask.cs | 2 +- .../Channels/ChannelManager.cs | 40 +- .../Channels/ChannelPostScanTask.cs | 136 +++++++ .../Connect/ConnectManager.cs | 4 +- .../Intros/DefaultIntroProvider.cs | 361 ++++++++++++++++++ .../Library/CoreResolutionIgnoreRule.cs | 3 +- .../Library/LibraryManager.cs | 35 +- .../Library/Resolvers/LocalTrailerResolver.cs | 12 +- .../Library/Resolvers/Movies/MovieResolver.cs | 8 +- .../Localization/JavaScript/javascript.json | 3 +- .../Localization/Server/server.json | 46 ++- ...MediaBrowser.Server.Implementations.csproj | 2 + .../Api/DashboardService.cs | 6 +- .../MediaBrowser.WebDashboard.csproj | 21 +- Nuget/MediaBrowser.Common.Internal.nuspec | 4 +- Nuget/MediaBrowser.Common.nuspec | 2 +- Nuget/MediaBrowser.Model.Signed.nuspec | 2 +- Nuget/MediaBrowser.Server.Core.nuspec | 4 +- 55 files changed, 1014 insertions(+), 141 deletions(-) create mode 100644 MediaBrowser.Controller/Providers/IExtrasProvider.cs create mode 100644 MediaBrowser.Model/Configuration/CinemaModeConfiguration.cs create mode 100644 MediaBrowser.Model/Entities/ExtraType.cs create mode 100644 MediaBrowser.Server.Implementations/Channels/ChannelPostScanTask.cs create mode 100644 MediaBrowser.Server.Implementations/Intros/DefaultIntroProvider.cs diff --git a/MediaBrowser.Api/ApiEntryPoint.cs b/MediaBrowser.Api/ApiEntryPoint.cs index 7c67f0a733..435bca0b8c 100644 --- a/MediaBrowser.Api/ApiEntryPoint.cs +++ b/MediaBrowser.Api/ApiEntryPoint.cs @@ -314,17 +314,16 @@ namespace MediaBrowser.Api /// /// The device id. /// The delete files. - /// if set to true [acquire lock]. /// Task. /// deviceId - internal Task KillTranscodingJobs(string deviceId, Func deleteFiles, bool acquireLock) + internal Task KillTranscodingJobs(string deviceId, Func deleteFiles) { if (string.IsNullOrEmpty(deviceId)) { throw new ArgumentNullException("deviceId"); } - return KillTranscodingJobs(j => string.Equals(deviceId, j.DeviceId, StringComparison.OrdinalIgnoreCase), deleteFiles, acquireLock); + return KillTranscodingJobs(j => string.Equals(deviceId, j.DeviceId, StringComparison.OrdinalIgnoreCase), deleteFiles); } /// @@ -332,9 +331,8 @@ namespace MediaBrowser.Api /// /// The kill job. /// The delete files. - /// if set to true [acquire lock]. /// Task. - internal async Task KillTranscodingJobs(Func killJob, Func deleteFiles, bool acquireLock) + internal async Task KillTranscodingJobs(Func killJob, Func deleteFiles) { var jobs = new List(); @@ -350,10 +348,7 @@ namespace MediaBrowser.Api return; } - if (acquireLock) - { - await TranscodingStartLock.WaitAsync(CancellationToken.None).ConfigureAwait(false); - } + await TranscodingStartLock.WaitAsync(CancellationToken.None).ConfigureAwait(false); try { @@ -364,10 +359,7 @@ namespace MediaBrowser.Api } finally { - if (acquireLock) - { - TranscodingStartLock.Release(); - } + TranscodingStartLock.Release(); } } diff --git a/MediaBrowser.Api/Playback/Hls/DynamicHlsService.cs b/MediaBrowser.Api/Playback/Hls/DynamicHlsService.cs index 2bb706769b..fb8168198d 100644 --- a/MediaBrowser.Api/Playback/Hls/DynamicHlsService.cs +++ b/MediaBrowser.Api/Playback/Hls/DynamicHlsService.cs @@ -139,7 +139,7 @@ namespace MediaBrowser.Api.Playback.Hls // If the playlist doesn't already exist, startup ffmpeg try { - await ApiEntryPoint.Instance.KillTranscodingJobs(j => j.Type == TranscodingJobType.Hls && string.Equals(j.DeviceId, request.DeviceId, StringComparison.OrdinalIgnoreCase), p => !string.Equals(p, playlistPath, StringComparison.OrdinalIgnoreCase), false).ConfigureAwait(false); + await ApiEntryPoint.Instance.KillTranscodingJobs(j => j.Type == TranscodingJobType.Hls && string.Equals(j.DeviceId, request.DeviceId, StringComparison.OrdinalIgnoreCase), p => !string.Equals(p, playlistPath, StringComparison.OrdinalIgnoreCase)).ConfigureAwait(false); if (currentTranscodingIndex.HasValue) { diff --git a/MediaBrowser.Api/Playback/Hls/HlsSegmentService.cs b/MediaBrowser.Api/Playback/Hls/HlsSegmentService.cs index 7e32246a29..a8d4c6b86f 100644 --- a/MediaBrowser.Api/Playback/Hls/HlsSegmentService.cs +++ b/MediaBrowser.Api/Playback/Hls/HlsSegmentService.cs @@ -72,7 +72,7 @@ namespace MediaBrowser.Api.Playback.Hls public void Delete(StopEncodingProcess request) { - var task = ApiEntryPoint.Instance.KillTranscodingJobs(request.DeviceId, path => true, true); + var task = ApiEntryPoint.Instance.KillTranscodingJobs(request.DeviceId, path => true); Task.WaitAll(task); } diff --git a/MediaBrowser.Api/UserLibrary/UserLibraryService.cs b/MediaBrowser.Api/UserLibrary/UserLibraryService.cs index b156b68d1a..ff86c8473b 100644 --- a/MediaBrowser.Api/UserLibrary/UserLibraryService.cs +++ b/MediaBrowser.Api/UserLibrary/UserLibraryService.cs @@ -566,13 +566,13 @@ namespace MediaBrowser.Api.UserLibrary /// /// The request. /// System.Object. - public object Get(GetIntros request) + public async Task Get(GetIntros request) { var user = _userManager.GetUserById(request.UserId); var item = string.IsNullOrEmpty(request.Id) ? user.RootFolder : _libraryManager.GetItemById(request.Id); - var items = _libraryManager.GetIntros(item, user); + var items = await _libraryManager.GetIntros(item, user).ConfigureAwait(false); // Get everything var fields = Enum.GetNames(typeof(ItemFields)) diff --git a/MediaBrowser.Common/Extensions/BaseExtensions.cs b/MediaBrowser.Common/Extensions/BaseExtensions.cs index 452c471593..be2fbffc64 100644 --- a/MediaBrowser.Common/Extensions/BaseExtensions.cs +++ b/MediaBrowser.Common/Extensions/BaseExtensions.cs @@ -1,4 +1,5 @@ using System; +using System.Globalization; using System.Security.Cryptography; using System.Text; using System.Text.RegularExpressions; @@ -54,6 +55,28 @@ namespace MediaBrowser.Common.Extensions return sb.ToString(); } + /// + /// Removes the accent. + /// + /// The text. + /// System.String. + public static string RemoveAccent(this string text) + { + var normalizedString = text.Normalize(NormalizationForm.FormD); + var stringBuilder = new StringBuilder(); + + foreach (var c in normalizedString) + { + var unicodeCategory = CharUnicodeInfo.GetUnicodeCategory(c); + if (unicodeCategory != UnicodeCategory.NonSpacingMark) + { + stringBuilder.Append(c); + } + } + + return stringBuilder.ToString().Normalize(NormalizationForm.FormC); + } + /// /// Gets the M d5. /// diff --git a/MediaBrowser.Controller/Channels/ChannelVideoItem.cs b/MediaBrowser.Controller/Channels/ChannelVideoItem.cs index 10e486e717..5d133c9834 100644 --- a/MediaBrowser.Controller/Channels/ChannelVideoItem.cs +++ b/MediaBrowser.Controller/Channels/ChannelVideoItem.cs @@ -1,4 +1,5 @@ using MediaBrowser.Controller.Entities; +using MediaBrowser.Controller.Providers; using MediaBrowser.Model.Channels; using MediaBrowser.Model.Configuration; using MediaBrowser.Model.Dto; @@ -9,7 +10,7 @@ using System.Linq; namespace MediaBrowser.Controller.Channels { - public class ChannelVideoItem : Video, IChannelMediaItem + public class ChannelVideoItem : Video, IChannelMediaItem, IHasLookupInfo { public string ExternalId { get; set; } @@ -87,5 +88,14 @@ namespace MediaBrowser.Controller.Channels return list; } + + public ChannelItemLookupInfo GetLookupInfo() + { + var info = GetItemLookupInfo(); + + info.ContentType = ContentType; + + return info; + } } } diff --git a/MediaBrowser.Controller/Channels/IChannelManager.cs b/MediaBrowser.Controller/Channels/IChannelManager.cs index 252e2aee53..07fb891324 100644 --- a/MediaBrowser.Controller/Channels/IChannelManager.cs +++ b/MediaBrowser.Controller/Channels/IChannelManager.cs @@ -59,6 +59,14 @@ namespace MediaBrowser.Controller.Channels /// Task{QueryResult{BaseItemDto}}. Task> GetChannels(ChannelQuery query, CancellationToken cancellationToken); + /// + /// Gets all media internal. + /// + /// The query. + /// The cancellation token. + /// Task<QueryResult<BaseItem>>. + Task> GetAllMediaInternal(AllChannelMediaQuery query, CancellationToken cancellationToken); + /// /// Gets all media. /// diff --git a/MediaBrowser.Controller/Channels/IChannelMediaItem.cs b/MediaBrowser.Controller/Channels/IChannelMediaItem.cs index db8e2b2927..e39d98e134 100644 --- a/MediaBrowser.Controller/Channels/IChannelMediaItem.cs +++ b/MediaBrowser.Controller/Channels/IChannelMediaItem.cs @@ -5,8 +5,6 @@ namespace MediaBrowser.Controller.Channels { public interface IChannelMediaItem : IChannelItem { - bool IsInfiniteStream { get; set; } - long? RunTimeTicks { get; set; } string MediaType { get; } diff --git a/MediaBrowser.Controller/Entities/Audio/Audio.cs b/MediaBrowser.Controller/Entities/Audio/Audio.cs index 25d41565ae..447328ea13 100644 --- a/MediaBrowser.Controller/Entities/Audio/Audio.cs +++ b/MediaBrowser.Controller/Entities/Audio/Audio.cs @@ -28,6 +28,7 @@ namespace MediaBrowser.Controller.Entities.Audio public string Container { get; set; } public int? TotalBitrate { get; set; } public List Tags { get; set; } + public ExtraType ExtraType { get; set; } public bool IsThemeMedia { get; set; } diff --git a/MediaBrowser.Controller/Entities/BaseItem.cs b/MediaBrowser.Controller/Entities/BaseItem.cs index 3830fa1c15..e75f17f9a0 100644 --- a/MediaBrowser.Controller/Entities/BaseItem.cs +++ b/MediaBrowser.Controller/Entities/BaseItem.cs @@ -41,16 +41,25 @@ namespace MediaBrowser.Controller.Entities /// /// The supported image extensions /// - public static readonly string[] SupportedImageExtensions = new[] { ".png", ".jpg", ".jpeg", ".tbn" }; + public static readonly string[] SupportedImageExtensions = { ".png", ".jpg", ".jpeg", ".tbn" }; /// /// The trailer folder name /// - public const string TrailerFolderName = "trailers"; - public const string ThemeSongsFolderName = "theme-music"; - public const string ThemeSongFilename = "theme"; - public const string ThemeVideosFolderName = "backdrops"; - public const string XbmcTrailerFileSuffix = "-trailer"; + public static string TrailerFolderName = "trailers"; + public static string ThemeSongsFolderName = "theme-music"; + public static string ThemeSongFilename = "theme"; + public static string ThemeVideosFolderName = "backdrops"; + + public static List> ExtraSuffixes = new List> + { + new KeyValuePair("-trailer", ExtraType.Trailer), + new KeyValuePair("-deleted", ExtraType.DeletedScene), + new KeyValuePair("-behindthescenes", ExtraType.BehindTheScenes), + new KeyValuePair("-interview", ExtraType.Interview), + new KeyValuePair("-scene", ExtraType.Scene), + new KeyValuePair("-sample", ExtraType.Sample) + }; public List ImageInfos { get; set; } @@ -167,7 +176,7 @@ namespace MediaBrowser.Controller.Entities { // Local trailer, special feature, theme video, etc. // An item that belongs to another item but is not part of the Parent-Child tree - return !IsFolder && Parent == null; + return !IsFolder && Parent == null && LocationType == LocationType.FileSystem; } } @@ -552,11 +561,24 @@ namespace MediaBrowser.Controller.Entities .Where(i => string.Equals(i.Name, TrailerFolderName, StringComparison.OrdinalIgnoreCase)) .SelectMany(i => i.EnumerateFiles("*", SearchOption.TopDirectoryOnly)) .ToList(); - - // Support plex/xbmc convention + + var extraTypes = new List { ExtraType.Trailer }; + var suffixes = ExtraSuffixes.Where(i => extraTypes.Contains(i.Value)) + .Select(i => i.Key) + .ToList(); + files.AddRange(fileSystemChildren.OfType() - .Where(i => FileSystem.GetFileNameWithoutExtension(i).EndsWith(XbmcTrailerFileSuffix, StringComparison.OrdinalIgnoreCase) && !string.Equals(Path, i.FullName, StringComparison.OrdinalIgnoreCase)) - ); + .Where(i => + { + var nameEithoutExtension = FileSystem.GetFileNameWithoutExtension(i); + + if (!suffixes.Any(s => nameEithoutExtension.EndsWith(s, StringComparison.OrdinalIgnoreCase))) + { + return false; + } + + return !string.Equals(Path, i.FullName, StringComparison.OrdinalIgnoreCase); + })); return LibraryManager.ResolvePaths(files, directoryService, null).Select(video => { @@ -568,12 +590,79 @@ namespace MediaBrowser.Controller.Entities video = dbItem; } + if (video != null) + { + video.ExtraType = ExtraType.Trailer; + } + return video; // Sort them so that the list can be easily compared for changes }).OrderBy(i => i.Path).ToList(); } + protected IEnumerable