From 1fb24df504fbb8e9208de13250cb09e5971f753f Mon Sep 17 00:00:00 2001 From: Luke Pulverenti Date: Wed, 18 Mar 2015 12:40:16 -0400 Subject: [PATCH] add query by PersonId --- .../Playback/Dash/MpegDashService.cs | 29 ++++++++++++------ .../Playback/Hls/DynamicHlsService.cs | 30 ++++++++++++++----- MediaBrowser.Api/UserLibrary/ItemsService.cs | 16 ++++++++++ .../Entities/InternalItemsQuery.cs | 2 ++ .../Entities/UserViewBuilder.cs | 14 ++++++++- MediaBrowser.Model/Querying/ItemQuery.cs | 3 +- .../Library/LibraryManager.cs | 2 +- .../Library/UserViewManager.cs | 10 ++++++- .../UserViews/DynamicImageProvider.cs | 1 + 9 files changed, 86 insertions(+), 21 deletions(-) diff --git a/MediaBrowser.Api/Playback/Dash/MpegDashService.cs b/MediaBrowser.Api/Playback/Dash/MpegDashService.cs index f2754fe7c..2655ff8ad 100644 --- a/MediaBrowser.Api/Playback/Dash/MpegDashService.cs +++ b/MediaBrowser.Api/Playback/Dash/MpegDashService.cs @@ -209,14 +209,14 @@ namespace MediaBrowser.Api.Playback.Dash ApiEntryPoint.Instance.KillTranscodingJobs(j => j.Type == TranscodingJobType && string.Equals(j.DeviceId, deviceId, StringComparison.OrdinalIgnoreCase), p => !string.Equals(p, playlistPath, StringComparison.OrdinalIgnoreCase)); } - private long GetPositionTicks(StreamState state, int segmentIndex) + private long GetPositionTicks(StreamState state, int requestedIndex) { - if (segmentIndex <= 1) + if (requestedIndex <= 0) { return 0; } - var startSeconds = segmentIndex * state.SegmentLength; + var startSeconds = requestedIndex * state.SegmentLength; return TimeSpan.FromSeconds(startSeconds).Ticks; } @@ -291,6 +291,13 @@ namespace MediaBrowser.Api.Playback.Dash public int? GetCurrentTranscodingIndex(string playlist, string segmentExtension) { + var job = ApiEntryPoint.Instance.GetTranscodingJob(playlist, TranscodingJobType); + + if (job == null || job.HasExited) + { + return null; + } + var file = GetLastTranscodingFiles(playlist, segmentExtension, FileSystem, 1).FirstOrDefault(); if (file == null) @@ -341,11 +348,11 @@ namespace MediaBrowser.Api.Playback.Dash } } - private string FindSegment(string playlist, string representationId, string segmentExtension, int index) + private string FindSegment(string playlist, string representationId, string segmentExtension, int requestedIndex) { var folder = Path.GetDirectoryName(playlist); - if (index == -1) + if (requestedIndex == -1) { var path = Path.Combine(folder, "0", "stream" + representationId + "-" + "init" + segmentExtension); return File.Exists(path) ? path : null; @@ -355,12 +362,16 @@ namespace MediaBrowser.Api.Playback.Dash { foreach (var subfolder in new DirectoryInfo(folder).EnumerateDirectories().ToList()) { + var subfolderName = Path.GetFileNameWithoutExtension(subfolder.FullName); int startNumber; - if (int.TryParse(Path.GetFileNameWithoutExtension(subfolder.FullName), NumberStyles.Any, UsCulture, out startNumber)) + if (int.TryParse(subfolderName, NumberStyles.Any, UsCulture, out startNumber)) { - var segmentIndex = index - startNumber + 1; - var path = Path.Combine(folder, "0", "stream" + representationId + "-" + segmentIndex.ToString("00000", CultureInfo.InvariantCulture) + segmentExtension); - return File.Exists(path) ? path : null; + var segmentIndex = requestedIndex - startNumber + 1; + var path = Path.Combine(folder, subfolderName, "stream" + representationId + "-" + segmentIndex.ToString("00000", CultureInfo.InvariantCulture) + segmentExtension); + if (File.Exists(path)) + { + return path; + } } } } diff --git a/MediaBrowser.Api/Playback/Hls/DynamicHlsService.cs b/MediaBrowser.Api/Playback/Hls/DynamicHlsService.cs index 719e7f156..32bbda8db 100644 --- a/MediaBrowser.Api/Playback/Hls/DynamicHlsService.cs +++ b/MediaBrowser.Api/Playback/Hls/DynamicHlsService.cs @@ -100,13 +100,13 @@ namespace MediaBrowser.Api.Playback.Hls var cancellationTokenSource = new CancellationTokenSource(); var cancellationToken = cancellationTokenSource.Token; - var index = int.Parse(segmentId, NumberStyles.Integer, UsCulture); + var requestedIndex = int.Parse(segmentId, NumberStyles.Integer, UsCulture); var state = await GetState(request, cancellationToken).ConfigureAwait(false); var playlistPath = Path.ChangeExtension(state.OutputFilePath, ".m3u8"); - var segmentPath = GetSegmentPath(playlistPath, index); + var segmentPath = GetSegmentPath(playlistPath, requestedIndex); var segmentLength = state.SegmentLength; var segmentExtension = GetSegmentFileExtension(state); @@ -116,7 +116,7 @@ namespace MediaBrowser.Api.Playback.Hls if (File.Exists(segmentPath)) { job = ApiEntryPoint.Instance.GetTranscodingJob(playlistPath, TranscodingJobType); - return await GetSegmentResult(playlistPath, segmentPath, index, segmentLength, job, cancellationToken).ConfigureAwait(false); + return await GetSegmentResult(playlistPath, segmentPath, requestedIndex, segmentLength, job, cancellationToken).ConfigureAwait(false); } await ApiEntryPoint.Instance.TranscodingStartLock.WaitAsync(cancellationTokenSource.Token).ConfigureAwait(false); @@ -125,13 +125,13 @@ namespace MediaBrowser.Api.Playback.Hls if (File.Exists(segmentPath)) { job = ApiEntryPoint.Instance.GetTranscodingJob(playlistPath, TranscodingJobType); - return await GetSegmentResult(playlistPath, segmentPath, index, segmentLength, job, cancellationToken).ConfigureAwait(false); + return await GetSegmentResult(playlistPath, segmentPath, requestedIndex, segmentLength, job, cancellationToken).ConfigureAwait(false); } else { var currentTranscodingIndex = GetCurrentTranscodingIndex(playlistPath, segmentExtension); var segmentGapRequiringTranscodingChange = 24/state.SegmentLength; - if (currentTranscodingIndex == null || index < currentTranscodingIndex.Value || (index - currentTranscodingIndex.Value) > segmentGapRequiringTranscodingChange) + if (currentTranscodingIndex == null || requestedIndex < currentTranscodingIndex.Value || (requestedIndex - currentTranscodingIndex.Value) > segmentGapRequiringTranscodingChange) { // If the playlist doesn't already exist, startup ffmpeg try @@ -143,8 +143,7 @@ namespace MediaBrowser.Api.Playback.Hls DeleteLastFile(playlistPath, segmentExtension, 0); } - var startSeconds = index * state.SegmentLength; - request.StartTimeTicks = TimeSpan.FromSeconds(startSeconds).Ticks; + request.StartTimeTicks = GetSeekPositionTicks(state, requestedIndex); job = await StartFfMpeg(state, playlistPath, cancellationTokenSource).ConfigureAwait(false); } @@ -171,11 +170,26 @@ namespace MediaBrowser.Api.Playback.Hls Logger.Info("returning {0}", segmentPath); job = job ?? ApiEntryPoint.Instance.GetTranscodingJob(playlistPath, TranscodingJobType); - return await GetSegmentResult(playlistPath, segmentPath, index, segmentLength, job, cancellationToken).ConfigureAwait(false); + return await GetSegmentResult(playlistPath, segmentPath, requestedIndex, segmentLength, job, cancellationToken).ConfigureAwait(false); + } + + private long GetSeekPositionTicks(StreamState state, int requestedIndex) + { + var startSeconds = requestedIndex * state.SegmentLength; + var position = TimeSpan.FromSeconds(startSeconds).Ticks; + + return position; } public int? GetCurrentTranscodingIndex(string playlist, string segmentExtension) { + var job = ApiEntryPoint.Instance.GetTranscodingJob(playlist, TranscodingJobType); + + if (job == null || job.HasExited) + { + return null; + } + var file = GetLastTranscodingFile(playlist, segmentExtension, FileSystem); if (file == null) diff --git a/MediaBrowser.Api/UserLibrary/ItemsService.cs b/MediaBrowser.Api/UserLibrary/ItemsService.cs index bdaad49e6..4d222c9bb 100644 --- a/MediaBrowser.Api/UserLibrary/ItemsService.cs +++ b/MediaBrowser.Api/UserLibrary/ItemsService.cs @@ -39,6 +39,9 @@ namespace MediaBrowser.Api.UserLibrary [ApiMember(Name = "Person", Description = "Optional. If specified, results will be filtered to include only those containing the specified person.", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET")] public string Person { get; set; } + [ApiMember(Name = "PersonIds", Description = "Optional. If specified, results will be filtered to include only those containing the specified person.", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET")] + public string PersonIds { get; set; } + /// /// If the Person filter is used, this can also be used to restrict to a specific person type /// @@ -244,6 +247,11 @@ namespace MediaBrowser.Api.UserLibrary return (PersonTypes ?? string.Empty).Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries); } + public string[] GetPersonIds() + { + return (PersonIds ?? string.Empty).Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries); + } + public VideoType[] GetVideoTypes() { var val = VideoTypes; @@ -477,6 +485,7 @@ namespace MediaBrowser.Api.UserLibrary Studios = request.GetStudios(), StudioIds = request.GetStudioIds(), Person = request.Person, + PersonIds = request.GetPersonIds(), PersonTypes = request.GetPersonTypes(), Years = request.GetYears(), ImageTypes = request.GetImageTypes().ToArray(), @@ -968,6 +977,13 @@ namespace MediaBrowser.Api.UserLibrary // Apply year filter var years = request.GetYears(); if (years.Length > 0 && !(i.ProductionYear.HasValue && years.Contains(i.ProductionYear.Value))) + { + return false; + } + + // Apply person filter + var personIds = request.GetPersonIds(); + if (personIds.Length > 0 && !(personIds.Any(v => i.People.Select(p => p.Name).Contains(v, StringComparer.OrdinalIgnoreCase)))) { return false; } diff --git a/MediaBrowser.Controller/Entities/InternalItemsQuery.cs b/MediaBrowser.Controller/Entities/InternalItemsQuery.cs index e1344009f..727f756f1 100644 --- a/MediaBrowser.Controller/Entities/InternalItemsQuery.cs +++ b/MediaBrowser.Controller/Entities/InternalItemsQuery.cs @@ -41,6 +41,7 @@ namespace MediaBrowser.Controller.Entities public string NameLessThan { get; set; } public string Person { get; set; } + public string[] PersonIds { get; set; } public string AdjacentTo { get; set; } public string[] PersonTypes { get; set; } @@ -87,6 +88,7 @@ namespace MediaBrowser.Controller.Entities VideoTypes = new VideoType[] { }; Years = new int[] { }; PersonTypes = new string[] { }; + PersonIds = new string[] { }; } } } diff --git a/MediaBrowser.Controller/Entities/UserViewBuilder.cs b/MediaBrowser.Controller/Entities/UserViewBuilder.cs index 2f182273b..f21add553 100644 --- a/MediaBrowser.Controller/Entities/UserViewBuilder.cs +++ b/MediaBrowser.Controller/Entities/UserViewBuilder.cs @@ -115,6 +115,7 @@ namespace MediaBrowser.Controller.Entities case CollectionType.Books: case CollectionType.Photos: case CollectionType.HomeVideos: + case CollectionType.MusicVideos: return GetResult(queryParent.GetChildren(user, true), queryParent, query); case CollectionType.Folders: @@ -1056,6 +1057,11 @@ namespace MediaBrowser.Controller.Entities return false; } + if (request.PersonIds.Length > 0) + { + return false; + } + if (request.Studios.Length > 0) { return false; @@ -1632,7 +1638,13 @@ namespace MediaBrowser.Controller.Entities } // Apply person filter - if (!string.IsNullOrEmpty(query.Person)) + if (query.PersonIds.Length > 0 && !(query.PersonIds.Any(v => item.People.Select(i => i.Name).Contains(v, StringComparer.OrdinalIgnoreCase)))) + { + return false; + } + + // Apply person filter + if (!string.IsNullOrWhiteSpace(query.Person)) { var personTypes = query.PersonTypes; diff --git a/MediaBrowser.Model/Querying/ItemQuery.cs b/MediaBrowser.Model/Querying/ItemQuery.cs index 6d26a2c0a..0cdf5ca7a 100644 --- a/MediaBrowser.Model/Querying/ItemQuery.cs +++ b/MediaBrowser.Model/Querying/ItemQuery.cs @@ -120,7 +120,7 @@ namespace MediaBrowser.Model.Querying /// Limit results to items containing a specific person /// /// The person. - public string Person { get; set; } + public string[] PersonIds { get; set; } /// /// If the Person filter is used, this can also be used to restrict to a specific person type @@ -307,6 +307,7 @@ namespace MediaBrowser.Model.Querying PersonTypes = new string[] { }; Ids = new string[] { }; ArtistIds = new string[] { }; + PersonIds = new string[] { }; ImageTypes = new ImageType[] { }; AirDays = new DayOfWeek[] { }; diff --git a/MediaBrowser.Server.Implementations/Library/LibraryManager.cs b/MediaBrowser.Server.Implementations/Library/LibraryManager.cs index 0fda026fd..1f82e7ef1 100644 --- a/MediaBrowser.Server.Implementations/Library/LibraryManager.cs +++ b/MediaBrowser.Server.Implementations/Library/LibraryManager.cs @@ -1673,7 +1673,7 @@ namespace MediaBrowser.Server.Implementations.Library throw new ArgumentNullException("viewType"); } - var id = GetNewItemId("36_namedview_" + name + user.Id.ToString("N") + (parentId ?? string.Empty), typeof(UserView)); + var id = GetNewItemId("37_namedview_" + name + user.Id.ToString("N") + (parentId ?? string.Empty), typeof(UserView)); var path = Path.Combine(ConfigurationManager.ApplicationPaths.InternalMetadataPath, "views", id.ToString("N")); diff --git a/MediaBrowser.Server.Implementations/Library/UserViewManager.cs b/MediaBrowser.Server.Implementations/Library/UserViewManager.cs index fb14628d8..e63a27551 100644 --- a/MediaBrowser.Server.Implementations/Library/UserViewManager.cs +++ b/MediaBrowser.Server.Implementations/Library/UserViewManager.cs @@ -71,7 +71,15 @@ namespace MediaBrowser.Server.Implementations.Library { var collectionFolder = folder as ICollectionFolder; var folderViewType = collectionFolder == null ? null : collectionFolder.CollectionType; - list.Add(await GetUserView(folder.Id, folder.Name, folderViewType, string.Empty, user, cancellationToken).ConfigureAwait(false)); + + if (string.IsNullOrWhiteSpace(folderViewType)) + { + list.Add(folder); + } + else + { + list.Add(await GetUserView(folder.Id, folder.Name, folderViewType, string.Empty, user, cancellationToken).ConfigureAwait(false)); + } } } else diff --git a/MediaBrowser.Server.Implementations/UserViews/DynamicImageProvider.cs b/MediaBrowser.Server.Implementations/UserViews/DynamicImageProvider.cs index 2af4c6a8c..b98dd2c49 100644 --- a/MediaBrowser.Server.Implementations/UserViews/DynamicImageProvider.cs +++ b/MediaBrowser.Server.Implementations/UserViews/DynamicImageProvider.cs @@ -231,6 +231,7 @@ namespace MediaBrowser.Server.Implementations.UserViews CollectionType.Books, CollectionType.Photos, CollectionType.HomeVideos, + CollectionType.MusicVideos, string.Empty };