From d43fd8c51dcd801959ed0581598efe2cd9314a9f Mon Sep 17 00:00:00 2001 From: Luke Pulverenti Date: Mon, 23 Sep 2013 14:28:07 -0400 Subject: updated nuget --- MediaBrowser.Controller/Entities/Folder.cs | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) (limited to 'MediaBrowser.Controller') diff --git a/MediaBrowser.Controller/Entities/Folder.cs b/MediaBrowser.Controller/Entities/Folder.cs index 0d91a2e86..326d30bd7 100644 --- a/MediaBrowser.Controller/Entities/Folder.cs +++ b/MediaBrowser.Controller/Entities/Folder.cs @@ -171,6 +171,25 @@ namespace MediaBrowser.Controller.Entities return ItemRepository.SaveChildren(Id, ActualChildren.Select(i => i.Id).ToList(), cancellationToken); } + /// + /// Clears the children. + /// + /// The cancellation token. + /// Task. + public Task ClearChildren(CancellationToken cancellationToken) + { + var items = ActualChildren.ToList(); + + ClearChildrenInternal(); + + foreach (var item in items) + { + LibraryManager.ReportItemRemoved(item); + } + + return ItemRepository.SaveChildren(Id, ActualChildren.Select(i => i.Id).ToList(), cancellationToken); + } + #region Indexing /// @@ -733,6 +752,11 @@ namespace MediaBrowser.Controller.Entities if (actualRemovals.Count > 0) { RemoveChildrenInternal(actualRemovals); + + foreach (var item in actualRemovals) + { + LibraryManager.ReportItemRemoved(item); + } } await LibraryManager.CreateItems(newItems, cancellationToken).ConfigureAwait(false); -- cgit v1.2.3 From b49764dbaafbbf11b6308ec675355696b9e58379 Mon Sep 17 00:00:00 2001 From: Luke Pulverenti Date: Tue, 24 Sep 2013 11:08:51 -0400 Subject: fixes #555 - Have clients report seek and queuing capabilities --- MediaBrowser.Api/UserLibrary/UserLibraryService.cs | 37 ++++++++++++++- .../Logging/NlogManager.cs | 18 +++----- .../ScheduledTasks/Tasks/DeleteLogFileTask.cs | 37 ++++++++------- .../ScheduledTasks/Tasks/ReloadLoggerTask.cs | 6 ++- MediaBrowser.Controller/Entities/Folder.cs | 5 +- .../MediaBrowser.Controller.csproj | 1 + MediaBrowser.Controller/Session/ISessionManager.cs | 7 ++- MediaBrowser.Controller/Session/PlaybackInfo.cs | 38 +++++++++++++++ MediaBrowser.Controller/Session/SessionInfo.cs | 13 ++++++ MediaBrowser.Model/ApiClient/IApiClient.cs | 4 +- MediaBrowser.Model/Session/SessionInfoDto.cs | 17 ++++++- .../Movies/FanArtMovieProvider.cs | 1 - .../Music/SoundtrackPostScanTask.cs | 4 +- MediaBrowser.Providers/TV/SeriesPostScanTask.cs | 4 +- .../Dto/DtoService.cs | 4 +- .../Library/LibraryManager.cs | 54 +++++++--------------- .../Library/Validators/PeoplePostScanTask.cs | 4 +- .../Persistence/SqliteItemRepository.cs | 15 +++--- .../Session/SessionManager.cs | 22 ++++++--- .../Session/SessionWebSocketListener.cs | 52 +++++++++++++++++---- .../WebSocket/AlchemyWebSocket.cs | 4 +- MediaBrowser.WebDashboard/ApiClient.js | 15 ++++-- MediaBrowser.WebDashboard/packages.config | 2 +- 23 files changed, 248 insertions(+), 116 deletions(-) create mode 100644 MediaBrowser.Controller/Session/PlaybackInfo.cs (limited to 'MediaBrowser.Controller') diff --git a/MediaBrowser.Api/UserLibrary/UserLibraryService.cs b/MediaBrowser.Api/UserLibrary/UserLibraryService.cs index ab3e2af19..9085a3ecf 100644 --- a/MediaBrowser.Api/UserLibrary/UserLibraryService.cs +++ b/MediaBrowser.Api/UserLibrary/UserLibraryService.cs @@ -186,7 +186,7 @@ namespace MediaBrowser.Api.UserLibrary [ApiMember(Name = "DatePlayed", Description = "The date the item was played (if any)", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "POST")] public DateTime? DatePlayed { get; set; } - + /// /// Gets or sets the id. /// @@ -224,6 +224,13 @@ namespace MediaBrowser.Api.UserLibrary [Api(Description = "Reports that a user has begun playing an item")] public class OnPlaybackStart : IReturnVoid { + public OnPlaybackStart() + { + // Have to default these until all clients have a chance to incorporate them + CanSeek = true; + QueueableMediaTypes = "Audio,Video,Book,Game"; + } + /// /// Gets or sets the user id. /// @@ -237,6 +244,20 @@ namespace MediaBrowser.Api.UserLibrary /// The id. [ApiMember(Name = "Id", Description = "Item Id", IsRequired = true, DataType = "string", ParameterType = "path", Verb = "POST")] public string Id { get; set; } + + /// + /// Gets or sets a value indicating whether this is likes. + /// + /// true if likes; otherwise, false. + [ApiMember(Name = "CanSeek", Description = "Indicates if the client can seek", IsRequired = false, DataType = "boolean", ParameterType = "query", Verb = "POST")] + public bool CanSeek { get; set; } + + /// + /// Gets or sets the id. + /// + /// The id. + [ApiMember(Name = "QueueableMediaTypes", Description = "A list of media types that can be queued from this item, comma delimited. Audio,Video,Book,Game", IsRequired = true, DataType = "string", ParameterType = "query", Verb = "POST", AllowMultiple = true)] + public string QueueableMediaTypes { get; set; } } /// @@ -378,6 +399,8 @@ namespace MediaBrowser.Api.UserLibrary /// The library manager. /// The user data repository. /// The item repo. + /// The session manager. + /// The dto service. /// jsonSerializer public UserLibraryService(IUserManager userManager, ILibraryManager libraryManager, IUserDataRepository userDataRepository, IItemRepository itemRepo, ISessionManager sessionManager, IDtoService dtoService) { @@ -665,7 +688,17 @@ namespace MediaBrowser.Api.UserLibrary var item = _dtoService.GetItemByDtoId(request.Id, user.Id); - _sessionManager.OnPlaybackStart(item, GetSession().Id); + var queueableMediaTypes = (request.QueueableMediaTypes ?? string.Empty); + + var info = new PlaybackInfo + { + CanSeek = request.CanSeek, + Item = item, + SessionId = GetSession().Id, + QueueableMediaTypes = queueableMediaTypes.Split(',').ToList() + }; + + _sessionManager.OnPlaybackStart(info); } /// diff --git a/MediaBrowser.Common.Implementations/Logging/NlogManager.cs b/MediaBrowser.Common.Implementations/Logging/NlogManager.cs index 109e85d80..e20f9bc13 100644 --- a/MediaBrowser.Common.Implementations/Logging/NlogManager.cs +++ b/MediaBrowser.Common.Implementations/Logging/NlogManager.cs @@ -5,7 +5,6 @@ using NLog.Targets; using System; using System.IO; using System.Linq; -using System.Threading.Tasks; namespace MediaBrowser.Common.Implementations.Logging { @@ -193,17 +192,14 @@ namespace MediaBrowser.Common.Implementations.Logging if (LoggerLoaded != null) { - Task.Run(() => + try { - try - { - LoggerLoaded(this, EventArgs.Empty); - } - catch (Exception ex) - { - GetLogger("Logger").ErrorException("Error in LoggerLoaded event", ex); - } - }); + LoggerLoaded(this, EventArgs.Empty); + } + catch (Exception ex) + { + GetLogger("Logger").ErrorException("Error in LoggerLoaded event", ex); + } } } } diff --git a/MediaBrowser.Common.Implementations/ScheduledTasks/Tasks/DeleteLogFileTask.cs b/MediaBrowser.Common.Implementations/ScheduledTasks/Tasks/DeleteLogFileTask.cs index 15f955723..bfd626adb 100644 --- a/MediaBrowser.Common.Implementations/ScheduledTasks/Tasks/DeleteLogFileTask.cs +++ b/MediaBrowser.Common.Implementations/ScheduledTasks/Tasks/DeleteLogFileTask.cs @@ -54,33 +54,32 @@ namespace MediaBrowser.Common.Implementations.ScheduledTasks.Tasks /// Task. public Task Execute(CancellationToken cancellationToken, IProgress progress) { - return Task.Run(() => - { - // Delete log files more than n days old - var minDateModified = DateTime.UtcNow.AddDays(-(ConfigurationManager.CommonConfiguration.LogFileRetentionDays)); + // Delete log files more than n days old + var minDateModified = DateTime.UtcNow.AddDays(-(ConfigurationManager.CommonConfiguration.LogFileRetentionDays)); + + var filesToDelete = new DirectoryInfo(ConfigurationManager.CommonApplicationPaths.LogDirectoryPath).EnumerateFileSystemInfos("*", SearchOption.AllDirectories) + .Where(f => f.LastWriteTimeUtc < minDateModified) + .ToList(); - var filesToDelete = new DirectoryInfo(ConfigurationManager.CommonApplicationPaths.LogDirectoryPath).EnumerateFileSystemInfos("*", SearchOption.AllDirectories) - .Where(f => f.LastWriteTimeUtc < minDateModified) - .ToList(); + var index = 0; - var index = 0; + foreach (var file in filesToDelete) + { + double percent = index; + percent /= filesToDelete.Count; - foreach (var file in filesToDelete) - { - double percent = index; - percent /= filesToDelete.Count; + progress.Report(100 * percent); - progress.Report(100 * percent); + cancellationToken.ThrowIfCancellationRequested(); - cancellationToken.ThrowIfCancellationRequested(); + File.Delete(file.FullName); - File.Delete(file.FullName); + index++; + } - index++; - } + progress.Report(100); - progress.Report(100); - }); + return Task.FromResult(true); } /// diff --git a/MediaBrowser.Common.Implementations/ScheduledTasks/Tasks/ReloadLoggerTask.cs b/MediaBrowser.Common.Implementations/ScheduledTasks/Tasks/ReloadLoggerTask.cs index e860834ec..00928255c 100644 --- a/MediaBrowser.Common.Implementations/ScheduledTasks/Tasks/ReloadLoggerTask.cs +++ b/MediaBrowser.Common.Implementations/ScheduledTasks/Tasks/ReloadLoggerTask.cs @@ -58,7 +58,11 @@ namespace MediaBrowser.Common.Implementations.ScheduledTasks.Tasks progress.Report(0); - return Task.Run(() => LogManager.ReloadLogger(ConfigurationManager.CommonConfiguration.EnableDebugLevelLogging ? LogSeverity.Debug : LogSeverity.Info)); + LogManager.ReloadLogger(ConfigurationManager.CommonConfiguration.EnableDebugLevelLogging + ? LogSeverity.Debug + : LogSeverity.Info); + + return Task.FromResult(true); } /// diff --git a/MediaBrowser.Controller/Entities/Folder.cs b/MediaBrowser.Controller/Entities/Folder.cs index 326d30bd7..0f090f587 100644 --- a/MediaBrowser.Controller/Entities/Folder.cs +++ b/MediaBrowser.Controller/Entities/Folder.cs @@ -16,7 +16,6 @@ using System.Linq; using System.Runtime.Serialization; using System.Threading; using System.Threading.Tasks; -using MoreLinq; namespace MediaBrowser.Controller.Entities { @@ -690,7 +689,7 @@ namespace MediaBrowser.Controller.Entities var options = new ParallelOptions { - MaxDegreeOfParallelism = 20 + MaxDegreeOfParallelism = 10 }; Parallel.ForEach(nonCachedChildren, options, child => @@ -805,7 +804,7 @@ namespace MediaBrowser.Controller.Entities foreach (var tuple in list) { - if (tasks.Count > 8) + if (tasks.Count > 5) { await Task.WhenAll(tasks).ConfigureAwait(false); } diff --git a/MediaBrowser.Controller/MediaBrowser.Controller.csproj b/MediaBrowser.Controller/MediaBrowser.Controller.csproj index f49bd8cf0..80cf82da1 100644 --- a/MediaBrowser.Controller/MediaBrowser.Controller.csproj +++ b/MediaBrowser.Controller/MediaBrowser.Controller.csproj @@ -165,6 +165,7 @@ + diff --git a/MediaBrowser.Controller/Session/ISessionManager.cs b/MediaBrowser.Controller/Session/ISessionManager.cs index 1976c653a..fba1d26e8 100644 --- a/MediaBrowser.Controller/Session/ISessionManager.cs +++ b/MediaBrowser.Controller/Session/ISessionManager.cs @@ -47,11 +47,9 @@ namespace MediaBrowser.Controller.Session /// /// Used to report that playback has started for an item /// - /// The item. - /// The session id. + /// The info. /// Task. - /// - Task OnPlaybackStart(BaseItem item, Guid sessionId); + Task OnPlaybackStart(PlaybackInfo info); /// /// Used to report playback progress for an item @@ -59,6 +57,7 @@ namespace MediaBrowser.Controller.Session /// The item. /// The position ticks. /// if set to true [is paused]. + /// if set to true [is muted]. /// The session id. /// Task. /// diff --git a/MediaBrowser.Controller/Session/PlaybackInfo.cs b/MediaBrowser.Controller/Session/PlaybackInfo.cs new file mode 100644 index 000000000..ab3111e76 --- /dev/null +++ b/MediaBrowser.Controller/Session/PlaybackInfo.cs @@ -0,0 +1,38 @@ +using MediaBrowser.Controller.Entities; +using System; +using System.Collections.Generic; + +namespace MediaBrowser.Controller.Session +{ + public class PlaybackInfo + { + public PlaybackInfo() + { + QueueableMediaTypes = new List(); + } + + /// + /// Gets or sets a value indicating whether this instance can seek. + /// + /// true if this instance can seek; otherwise, false. + public bool CanSeek { get; set; } + + /// + /// Gets or sets the queueable media types. + /// + /// The queueable media types. + public List QueueableMediaTypes { get; set; } + + /// + /// Gets or sets the item. + /// + /// The item. + public BaseItem Item { get; set; } + + /// + /// Gets or sets the session id. + /// + /// The session id. + public Guid SessionId { get; set; } + } +} diff --git a/MediaBrowser.Controller/Session/SessionInfo.cs b/MediaBrowser.Controller/Session/SessionInfo.cs index 6c0f1a085..ba6d3d0ac 100644 --- a/MediaBrowser.Controller/Session/SessionInfo.cs +++ b/MediaBrowser.Controller/Session/SessionInfo.cs @@ -15,8 +15,21 @@ namespace MediaBrowser.Controller.Session public SessionInfo() { WebSockets = new List(); + QueueableMediaTypes = new List(); } + /// + /// Gets or sets a value indicating whether this instance can seek. + /// + /// true if this instance can seek; otherwise, false. + public bool CanSeek { get; set; } + + /// + /// Gets or sets the queueable media types. + /// + /// The queueable media types. + public List QueueableMediaTypes { get; set; } + /// /// Gets or sets the id. /// diff --git a/MediaBrowser.Model/ApiClient/IApiClient.cs b/MediaBrowser.Model/ApiClient/IApiClient.cs index 03ea79b3b..4a459cac8 100644 --- a/MediaBrowser.Model/ApiClient/IApiClient.cs +++ b/MediaBrowser.Model/ApiClient/IApiClient.cs @@ -497,9 +497,11 @@ namespace MediaBrowser.Model.ApiClient /// /// The item id. /// The user id. + /// if set to true [is seekable]. + /// The list of media types that the client is capable of queuing onto the playlist. See MediaType class. /// Task{UserItemDataDto}. /// itemId - Task ReportPlaybackStartAsync(string itemId, string userId); + Task ReportPlaybackStartAsync(string itemId, string userId, bool isSeekable, List queueableMediaTypes); /// /// Reports playback progress to the server diff --git a/MediaBrowser.Model/Session/SessionInfoDto.cs b/MediaBrowser.Model/Session/SessionInfoDto.cs index f9b0e0abd..02b7f0226 100644 --- a/MediaBrowser.Model/Session/SessionInfoDto.cs +++ b/MediaBrowser.Model/Session/SessionInfoDto.cs @@ -1,11 +1,24 @@ -using System.ComponentModel; -using MediaBrowser.Model.Entities; +using MediaBrowser.Model.Entities; using System; +using System.Collections.Generic; +using System.ComponentModel; namespace MediaBrowser.Model.Session { public class SessionInfoDto : INotifyPropertyChanged { + /// + /// Gets or sets a value indicating whether this instance can seek. + /// + /// true if this instance can seek; otherwise, false. + public bool CanSeek { get; set; } + + /// + /// Gets or sets the queueable media types. + /// + /// The queueable media types. + public List QueueableMediaTypes { get; set; } + /// /// Gets or sets the id. /// diff --git a/MediaBrowser.Providers/Movies/FanArtMovieProvider.cs b/MediaBrowser.Providers/Movies/FanArtMovieProvider.cs index fefcd8371..adc013699 100644 --- a/MediaBrowser.Providers/Movies/FanArtMovieProvider.cs +++ b/MediaBrowser.Providers/Movies/FanArtMovieProvider.cs @@ -1,5 +1,4 @@ using MediaBrowser.Common.Configuration; -using MediaBrowser.Common.Extensions; using MediaBrowser.Common.IO; using MediaBrowser.Common.Net; using MediaBrowser.Controller.Configuration; diff --git a/MediaBrowser.Providers/Music/SoundtrackPostScanTask.cs b/MediaBrowser.Providers/Music/SoundtrackPostScanTask.cs index 18868d3ea..e18351248 100644 --- a/MediaBrowser.Providers/Music/SoundtrackPostScanTask.cs +++ b/MediaBrowser.Providers/Music/SoundtrackPostScanTask.cs @@ -23,7 +23,9 @@ namespace MediaBrowser.Providers.Music public Task Run(IProgress progress, CancellationToken cancellationToken) { - return Task.Run(() => RunInternal(progress, cancellationToken)); + RunInternal(progress, cancellationToken); + + return Task.FromResult(true); } private void RunInternal(IProgress progress, CancellationToken cancellationToken) diff --git a/MediaBrowser.Providers/TV/SeriesPostScanTask.cs b/MediaBrowser.Providers/TV/SeriesPostScanTask.cs index a781551de..2b73ba1f7 100644 --- a/MediaBrowser.Providers/TV/SeriesPostScanTask.cs +++ b/MediaBrowser.Providers/TV/SeriesPostScanTask.cs @@ -21,7 +21,9 @@ namespace MediaBrowser.Providers.TV public Task Run(IProgress progress, CancellationToken cancellationToken) { - return Task.Run(() => RunInternal(progress, cancellationToken)); + RunInternal(progress, cancellationToken); + + return Task.FromResult(true); } private void RunInternal(IProgress progress, CancellationToken cancellationToken) diff --git a/MediaBrowser.Server.Implementations/Dto/DtoService.cs b/MediaBrowser.Server.Implementations/Dto/DtoService.cs index e5260004a..a5f54b938 100644 --- a/MediaBrowser.Server.Implementations/Dto/DtoService.cs +++ b/MediaBrowser.Server.Implementations/Dto/DtoService.cs @@ -237,7 +237,9 @@ namespace MediaBrowser.Server.Implementations.Dto NowViewingItemId = session.NowViewingItemId, NowViewingItemName = session.NowViewingItemName, NowViewingItemType = session.NowViewingItemType, - ApplicationVersion = session.ApplicationVersion + ApplicationVersion = session.ApplicationVersion, + CanSeek = session.CanSeek, + QueueableMediaTypes = session.QueueableMediaTypes }; if (session.NowPlayingItem != null) diff --git a/MediaBrowser.Server.Implementations/Library/LibraryManager.cs b/MediaBrowser.Server.Implementations/Library/LibraryManager.cs index a5b792726..1bc3f1094 100644 --- a/MediaBrowser.Server.Implementations/Library/LibraryManager.cs +++ b/MediaBrowser.Server.Implementations/Library/LibraryManager.cs @@ -829,10 +829,6 @@ namespace MediaBrowser.Server.Implementations.Library /// Task. public async Task ValidatePeople(CancellationToken cancellationToken, IProgress progress) { - const int maxTasks = 3; - - var tasks = new List(); - var people = RootFolder.RecursiveChildren .SelectMany(c => c.People) .DistinctBy(p => p.Name, StringComparer.OrdinalIgnoreCase) @@ -842,47 +838,27 @@ namespace MediaBrowser.Server.Implementations.Library foreach (var person in people) { - if (tasks.Count > maxTasks) + cancellationToken.ThrowIfCancellationRequested(); + + try { - await Task.WhenAll(tasks).ConfigureAwait(false); - tasks.Clear(); + var item = GetPerson(person.Name); - // Safe cancellation point, when there are no pending tasks - cancellationToken.ThrowIfCancellationRequested(); + await item.RefreshMetadata(cancellationToken).ConfigureAwait(false); } - - // Avoid accessing the foreach variable within the closure - var currentPerson = person; - - tasks.Add(Task.Run(async () => + catch (IOException ex) { - cancellationToken.ThrowIfCancellationRequested(); - - try - { - var item = GetPerson(currentPerson.Name); - - await item.RefreshMetadata(cancellationToken).ConfigureAwait(false); - } - catch (IOException ex) - { - _logger.ErrorException("Error validating IBN entry {0}", ex, currentPerson.Name); - } + _logger.ErrorException("Error validating IBN entry {0}", ex, person.Name); + } - // Update progress - lock (progress) - { - numComplete++; - double percent = numComplete; - percent /= people.Count; + // Update progress + numComplete++; + double percent = numComplete; + percent /= people.Count; - progress.Report(100 * percent); - } - })); + progress.Report(100 * percent); } - await Task.WhenAll(tasks).ConfigureAwait(false); - progress.Report(100); _logger.Info("People validation complete"); @@ -956,7 +932,9 @@ namespace MediaBrowser.Server.Implementations.Library public Task ValidateMediaLibrary(IProgress progress, CancellationToken cancellationToken) { // Just run the scheduled task so that the user can see it - return Task.Run(() => _taskManager.CancelIfRunningAndQueue()); + _taskManager.CancelIfRunningAndQueue(); + + return Task.FromResult(true); } /// diff --git a/MediaBrowser.Server.Implementations/Library/Validators/PeoplePostScanTask.cs b/MediaBrowser.Server.Implementations/Library/Validators/PeoplePostScanTask.cs index efefaeba3..dc96632f6 100644 --- a/MediaBrowser.Server.Implementations/Library/Validators/PeoplePostScanTask.cs +++ b/MediaBrowser.Server.Implementations/Library/Validators/PeoplePostScanTask.cs @@ -41,7 +41,9 @@ namespace MediaBrowser.Server.Implementations.Library.Validators /// Task. public Task Run(IProgress progress, CancellationToken cancellationToken) { - return Task.Run(() => RunInternal(progress, cancellationToken)); + RunInternal(progress, cancellationToken); + + return Task.FromResult(true); } private void RunInternal(IProgress progress, CancellationToken cancellationToken) diff --git a/MediaBrowser.Server.Implementations/Persistence/SqliteItemRepository.cs b/MediaBrowser.Server.Implementations/Persistence/SqliteItemRepository.cs index f4f5f08e4..9c5cf6f1c 100644 --- a/MediaBrowser.Server.Implementations/Persistence/SqliteItemRepository.cs +++ b/MediaBrowser.Server.Implementations/Persistence/SqliteItemRepository.cs @@ -333,17 +333,16 @@ namespace MediaBrowser.Server.Implementations.Persistence /// Task. public Task SaveCriticReviews(Guid itemId, IEnumerable criticReviews) { - return Task.Run(() => + if (!Directory.Exists(_criticReviewsPath)) { - if (!Directory.Exists(_criticReviewsPath)) - { - Directory.CreateDirectory(_criticReviewsPath); - } + Directory.CreateDirectory(_criticReviewsPath); + } - var path = Path.Combine(_criticReviewsPath, itemId + ".json"); + var path = Path.Combine(_criticReviewsPath, itemId + ".json"); + + _jsonSerializer.SerializeToFile(criticReviews.ToList(), path); - _jsonSerializer.SerializeToFile(criticReviews.ToList(), path); - }); + return Task.FromResult(true); } /// diff --git a/MediaBrowser.Server.Implementations/Session/SessionManager.cs b/MediaBrowser.Server.Implementations/Session/SessionManager.cs index ce757d142..65ec02d12 100644 --- a/MediaBrowser.Server.Implementations/Session/SessionManager.cs +++ b/MediaBrowser.Server.Implementations/Session/SessionManager.cs @@ -207,21 +207,29 @@ namespace MediaBrowser.Server.Implementations.Session /// /// Used to report that playback has started for an item /// - /// The item. - /// The session id. + /// The info. /// Task. - /// - public async Task OnPlaybackStart(BaseItem item, Guid sessionId) + /// info + public async Task OnPlaybackStart(PlaybackInfo info) { - if (item == null) + if (info == null) { - throw new ArgumentNullException(); + throw new ArgumentNullException("info"); + } + if (info.SessionId == Guid.Empty) + { + throw new ArgumentNullException("info"); } - var session = Sessions.First(i => i.Id.Equals(sessionId)); + var session = Sessions.First(i => i.Id.Equals(info.SessionId)); + + var item = info.Item; UpdateNowPlayingItem(session, item, false, false); + session.CanSeek = info.CanSeek; + session.QueueableMediaTypes = info.QueueableMediaTypes; + var key = item.GetUserDataKey(); var user = session.User; diff --git a/MediaBrowser.Server.Implementations/Session/SessionWebSocketListener.cs b/MediaBrowser.Server.Implementations/Session/SessionWebSocketListener.cs index 2a4361e61..95eb5948f 100644 --- a/MediaBrowser.Server.Implementations/Session/SessionWebSocketListener.cs +++ b/MediaBrowser.Server.Implementations/Session/SessionWebSocketListener.cs @@ -101,16 +101,7 @@ namespace MediaBrowser.Server.Implementations.Session } else if (string.Equals(message.MessageType, "PlaybackStart", StringComparison.OrdinalIgnoreCase)) { - _logger.Debug("Received PlaybackStart message"); - - var session = _sessionManager.Sessions.FirstOrDefault(i => i.WebSockets.Contains(message.Connection)); - - if (session != null && session.User != null) - { - var item = _dtoService.GetItemByDtoId(message.Data); - - _sessionManager.OnPlaybackStart(item, session.Id); - } + ReportPlaybackStart(message); } else if (string.Equals(message.MessageType, "PlaybackProgress", StringComparison.OrdinalIgnoreCase)) { @@ -170,5 +161,46 @@ namespace MediaBrowser.Server.Implementations.Session return _trueTaskResult; } + + /// + /// Reports the playback start. + /// + /// The message. + private void ReportPlaybackStart(WebSocketMessageInfo message) + { + _logger.Debug("Received PlaybackStart message"); + + var session = _sessionManager.Sessions + .FirstOrDefault(i => i.WebSockets.Contains(message.Connection)); + + if (session != null && session.User != null) + { + var vals = message.Data.Split('|'); + + var item = _dtoService.GetItemByDtoId(vals[0]); + + var queueableMediaTypes = string.Empty; + var canSeek = true; + + if (vals.Length > 1) + { + canSeek = string.Equals(vals[1], "true", StringComparison.OrdinalIgnoreCase); + } + if (vals.Length > 2) + { + queueableMediaTypes = vals[2]; + } + + var info = new PlaybackInfo + { + CanSeek = canSeek, + Item = item, + SessionId = session.Id, + QueueableMediaTypes = queueableMediaTypes.Split(',').ToList() + }; + + _sessionManager.OnPlaybackStart(info); + } + } } } diff --git a/MediaBrowser.Server.Implementations/WebSocket/AlchemyWebSocket.cs b/MediaBrowser.Server.Implementations/WebSocket/AlchemyWebSocket.cs index 958201625..de998254c 100644 --- a/MediaBrowser.Server.Implementations/WebSocket/AlchemyWebSocket.cs +++ b/MediaBrowser.Server.Implementations/WebSocket/AlchemyWebSocket.cs @@ -92,7 +92,9 @@ namespace MediaBrowser.Server.Implementations.WebSocket /// Task. public Task SendAsync(byte[] bytes, WebSocketMessageType type, bool endOfMessage, CancellationToken cancellationToken) { - return Task.Run(() => UserContext.Send(bytes)); + UserContext.Send(bytes); + + return Task.FromResult(true); } /// diff --git a/MediaBrowser.WebDashboard/ApiClient.js b/MediaBrowser.WebDashboard/ApiClient.js index d139adfc3..189812a3c 100644 --- a/MediaBrowser.WebDashboard/ApiClient.js +++ b/MediaBrowser.WebDashboard/ApiClient.js @@ -3200,7 +3200,7 @@ MediaBrowser.ApiClient = function ($, navigator, JSON, WebSocket, setTimeout, wi * @param {String} userId * @param {String} itemId */ - self.reportPlaybackStart = function (userId, itemId) { + self.reportPlaybackStart = function (userId, itemId, canSeek, queueableMediaTypes) { if (!userId) { throw new Error("null userId"); @@ -3210,17 +3210,26 @@ MediaBrowser.ApiClient = function ($, navigator, JSON, WebSocket, setTimeout, wi throw new Error("null itemId"); } + canSeek = canSeek || false; + queueableMediaTypes = queueableMediaTypes || ''; + if (self.isWebSocketOpen()) { var deferred = $.Deferred(); - self.sendWebSocketMessage("PlaybackStart", itemId); + var msg = [itemId, canSeek, queueableMediaTypes]; + + self.sendWebSocketMessage("PlaybackStart", msg.join('|')); deferred.resolveWith(null, []); return deferred.promise(); } - var url = self.getUrl("Users/" + userId + "/PlayingItems/" + itemId); + var url = self.getUrl("Users/" + userId + "/PlayingItems/" + itemId, { + + CanSeek: canSeek, + QueueableMediaTypes: queueableMediaTypes + }); return self.ajax({ type: "POST", diff --git a/MediaBrowser.WebDashboard/packages.config b/MediaBrowser.WebDashboard/packages.config index 25b4f7b47..1c5a0f818 100644 --- a/MediaBrowser.WebDashboard/packages.config +++ b/MediaBrowser.WebDashboard/packages.config @@ -1,6 +1,6 @@  - + \ No newline at end of file -- cgit v1.2.3 From c61cc4a304978a59f66c86c3618f8f6dd8ccca7b Mon Sep 17 00:00:00 2001 From: Luke Pulverenti Date: Tue, 24 Sep 2013 11:42:30 -0400 Subject: support more kinds of remote control besides web socket --- MediaBrowser.Api/SessionsService.cs | 40 +------------ .../MediaBrowser.Controller.csproj | 1 + MediaBrowser.Controller/Session/ISessionManager.cs | 17 ++++++ .../Session/ISessionRemoteController.cs | 25 +++++++++ .../MediaBrowser.Server.Implementations.csproj | 1 + .../Session/SessionManager.cs | 65 ++++++++++++++++++++-- .../Session/WebSocketController.cs | 52 +++++++++++++++++ MediaBrowser.ServerApplication/ApplicationHost.cs | 7 ++- 8 files changed, 163 insertions(+), 45 deletions(-) create mode 100644 MediaBrowser.Controller/Session/ISessionRemoteController.cs create mode 100644 MediaBrowser.Server.Implementations/Session/WebSocketController.cs (limited to 'MediaBrowser.Controller') diff --git a/MediaBrowser.Api/SessionsService.cs b/MediaBrowser.Api/SessionsService.cs index cad3c4384..b93b5326e 100644 --- a/MediaBrowser.Api/SessionsService.cs +++ b/MediaBrowser.Api/SessionsService.cs @@ -325,49 +325,11 @@ namespace MediaBrowser.Api /// The request. public void Post(SendSystemCommand request) { - var task = SendSystemCommand(request); + var task = _sessionManager.SendSystemCommand(request.Id, request.Command, CancellationToken.None); Task.WaitAll(task); } - private async Task SendSystemCommand(SendSystemCommand request) - { - var session = _sessionManager.Sessions.FirstOrDefault(i => i.Id == request.Id); - - if (session == null) - { - throw new ResourceNotFoundException(string.Format("Session {0} not found.", request.Id)); - } - - if (!session.SupportsRemoteControl) - { - throw new ArgumentException(string.Format("Session {0} does not support remote control.", session.Id)); - } - - var socket = session.WebSockets.OrderByDescending(i => i.LastActivityDate).FirstOrDefault(i => i.State == WebSocketState.Open); - - if (socket != null) - { - try - { - await socket.SendAsync(new WebSocketMessage - { - MessageType = "SystemCommand", - Data = request.Command.ToString() - - }, CancellationToken.None).ConfigureAwait(false); - } - catch (Exception ex) - { - Logger.ErrorException("Error sending web socket message", ex); - } - } - else - { - throw new InvalidOperationException("The requested session does not have an open web socket."); - } - } - /// /// Posts the specified request. /// diff --git a/MediaBrowser.Controller/MediaBrowser.Controller.csproj b/MediaBrowser.Controller/MediaBrowser.Controller.csproj index 80cf82da1..b5ad862be 100644 --- a/MediaBrowser.Controller/MediaBrowser.Controller.csproj +++ b/MediaBrowser.Controller/MediaBrowser.Controller.csproj @@ -165,6 +165,7 @@ + diff --git a/MediaBrowser.Controller/Session/ISessionManager.cs b/MediaBrowser.Controller/Session/ISessionManager.cs index fba1d26e8..f8f7ded2b 100644 --- a/MediaBrowser.Controller/Session/ISessionManager.cs +++ b/MediaBrowser.Controller/Session/ISessionManager.cs @@ -1,7 +1,9 @@ using MediaBrowser.Controller.Entities; using MediaBrowser.Controller.Library; +using MediaBrowser.Model.Session; using System; using System.Collections.Generic; +using System.Threading; using System.Threading.Tasks; namespace MediaBrowser.Controller.Session @@ -11,6 +13,12 @@ namespace MediaBrowser.Controller.Session /// public interface ISessionManager { + /// + /// Adds the parts. + /// + /// The remote controllers. + void AddParts(IEnumerable remoteControllers); + /// /// Occurs when [playback start]. /// @@ -72,5 +80,14 @@ namespace MediaBrowser.Controller.Session /// Task. /// Task OnPlaybackStopped(BaseItem item, long? positionTicks, Guid sessionId); + + /// + /// Sends the system command. + /// + /// The session id. + /// The command. + /// The cancellation token. + /// Task. + Task SendSystemCommand(Guid sessionId, SystemCommand command, CancellationToken cancellationToken); } } \ No newline at end of file diff --git a/MediaBrowser.Controller/Session/ISessionRemoteController.cs b/MediaBrowser.Controller/Session/ISessionRemoteController.cs new file mode 100644 index 000000000..1f6faeb9c --- /dev/null +++ b/MediaBrowser.Controller/Session/ISessionRemoteController.cs @@ -0,0 +1,25 @@ +using MediaBrowser.Model.Session; +using System.Threading; +using System.Threading.Tasks; + +namespace MediaBrowser.Controller.Session +{ + public interface ISessionRemoteController + { + /// + /// Supportses the specified session. + /// + /// The session. + /// true if XXXX, false otherwise + bool Supports(SessionInfo session); + + /// + /// Sends the system command. + /// + /// The session. + /// The command. + /// The cancellation token. + /// Task. + Task SendSystemCommand(SessionInfo session, SystemCommand command, CancellationToken cancellationToken); + } +} diff --git a/MediaBrowser.Server.Implementations/MediaBrowser.Server.Implementations.csproj b/MediaBrowser.Server.Implementations/MediaBrowser.Server.Implementations.csproj index 9d2fc8c6b..3c2021750 100644 --- a/MediaBrowser.Server.Implementations/MediaBrowser.Server.Implementations.csproj +++ b/MediaBrowser.Server.Implementations/MediaBrowser.Server.Implementations.csproj @@ -183,6 +183,7 @@ Code + diff --git a/MediaBrowser.Server.Implementations/Session/SessionManager.cs b/MediaBrowser.Server.Implementations/Session/SessionManager.cs index 65ec02d12..5b0d957ae 100644 --- a/MediaBrowser.Server.Implementations/Session/SessionManager.cs +++ b/MediaBrowser.Server.Implementations/Session/SessionManager.cs @@ -1,4 +1,5 @@ using MediaBrowser.Common.Events; +using MediaBrowser.Common.Extensions; using MediaBrowser.Controller.Configuration; using MediaBrowser.Controller.Entities; using MediaBrowser.Controller.Entities.Audio; @@ -6,6 +7,7 @@ using MediaBrowser.Controller.Library; using MediaBrowser.Controller.Persistence; using MediaBrowser.Controller.Session; using MediaBrowser.Model.Logging; +using MediaBrowser.Model.Session; using System; using System.Collections.Concurrent; using System.Collections.Generic; @@ -75,6 +77,12 @@ namespace MediaBrowser.Server.Implementations.Session _userRepository = userRepository; } + private List _remoteControllers; + public void AddParts(IEnumerable remoteControllers) + { + _remoteControllers = remoteControllers.ToList(); + } + /// /// Gets all connections. /// @@ -122,7 +130,7 @@ namespace MediaBrowser.Server.Implementations.Session var activityDate = DateTime.UtcNow; var session = GetSessionInfo(clientType, appVersion, deviceId, deviceName, user); - + session.LastActivityDate = activityDate; if (user == null) @@ -233,7 +241,7 @@ namespace MediaBrowser.Server.Implementations.Session var key = item.GetUserDataKey(); var user = session.User; - + var data = _userDataRepository.GetUserData(user.Id, key); data.PlayCount++; @@ -321,7 +329,7 @@ namespace MediaBrowser.Server.Implementations.Session { throw new ArgumentOutOfRangeException("positionTicks"); } - + var session = Sessions.First(i => i.Id.Equals(sessionId)); RemoveNowPlayingItem(session, item); @@ -329,7 +337,7 @@ namespace MediaBrowser.Server.Implementations.Session var key = item.GetUserDataKey(); var user = session.User; - + var data = _userDataRepository.GetUserData(user.Id, key); if (positionTicks.HasValue) @@ -408,5 +416,54 @@ namespace MediaBrowser.Server.Implementations.Session data.PlaybackPositionTicks = positionTicks; } + + /// + /// Gets the session for remote control. + /// + /// The session id. + /// SessionInfo. + /// + private SessionInfo GetSessionForRemoteControl(Guid sessionId) + { + var session = Sessions.First(i => i.Id.Equals(sessionId)); + + if (session == null) + { + throw new ResourceNotFoundException(string.Format("Session {0} not found.", sessionId)); + } + + if (!session.SupportsRemoteControl) + { + throw new ArgumentException(string.Format("Session {0} does not support remote control.", session.Id)); + } + + return session; + } + + /// + /// Gets the controllers. + /// + /// The session. + /// IEnumerable{ISessionRemoteController}. + private IEnumerable GetControllers(SessionInfo session) + { + return _remoteControllers.Where(i => i.Supports(session)); + } + + /// + /// Sends the system command. + /// + /// The session id. + /// The command. + /// The cancellation token. + /// Task. + public Task SendSystemCommand(Guid sessionId, SystemCommand command, CancellationToken cancellationToken) + { + var session = GetSessionForRemoteControl(sessionId); + + var tasks = GetControllers(session).Select(i => i.SendSystemCommand(session, command, cancellationToken)); + + return Task.WhenAll(tasks); + } } } diff --git a/MediaBrowser.Server.Implementations/Session/WebSocketController.cs b/MediaBrowser.Server.Implementations/Session/WebSocketController.cs new file mode 100644 index 000000000..daa4c7d81 --- /dev/null +++ b/MediaBrowser.Server.Implementations/Session/WebSocketController.cs @@ -0,0 +1,52 @@ +using MediaBrowser.Controller.Session; +using MediaBrowser.Model.Logging; +using MediaBrowser.Model.Net; +using MediaBrowser.Model.Session; +using System; +using System.Linq; +using System.Threading; +using System.Threading.Tasks; + +namespace MediaBrowser.Server.Implementations.Session +{ + public class WebSocketController : ISessionRemoteController + { + private readonly ILogger _logger; + + public WebSocketController(ILogger logger) + { + _logger = logger; + } + + public bool Supports(SessionInfo session) + { + return session.WebSockets.Any(i => i.State == WebSocketState.Open); + } + + public async Task SendSystemCommand(SessionInfo session, SystemCommand command, CancellationToken cancellationToken) + { + var socket = session.WebSockets.OrderByDescending(i => i.LastActivityDate).FirstOrDefault(i => i.State == WebSocketState.Open); + + if (socket != null) + { + try + { + await socket.SendAsync(new WebSocketMessage + { + MessageType = "SystemCommand", + Data = command.ToString() + + }, cancellationToken).ConfigureAwait(false); + } + catch (Exception ex) + { + _logger.ErrorException("Error sending web socket message", ex); + } + } + else + { + throw new InvalidOperationException("The requested session does not have an open web socket."); + } + } + } +} diff --git a/MediaBrowser.ServerApplication/ApplicationHost.cs b/MediaBrowser.ServerApplication/ApplicationHost.cs index 7a99693a6..e96516603 100644 --- a/MediaBrowser.ServerApplication/ApplicationHost.cs +++ b/MediaBrowser.ServerApplication/ApplicationHost.cs @@ -161,6 +161,7 @@ namespace MediaBrowser.ServerApplication private IMediaEncoder MediaEncoder { get; set; } private IIsoManager IsoManager { get; set; } + private ISessionManager SessionManager { get; set; } private ILocalizationManager LocalizationManager { get; set; } @@ -286,8 +287,8 @@ namespace MediaBrowser.ServerApplication RegisterSingleInstance(() => new LuceneSearchEngine(ApplicationPaths, LogManager, LibraryManager)); - var clientConnectionManager = new SessionManager(UserDataRepository, ServerConfigurationManager, Logger, UserRepository); - RegisterSingleInstance(clientConnectionManager); + SessionManager = new SessionManager(UserDataRepository, ServerConfigurationManager, Logger, UserRepository); + RegisterSingleInstance(SessionManager); HttpServer = await _httpServerCreationTask.ConfigureAwait(false); RegisterSingleInstance(HttpServer, false); @@ -477,6 +478,8 @@ namespace MediaBrowser.ServerApplication IsoManager.AddParts(GetExports()); + SessionManager.AddParts(GetExports()); + ImageProcessor.AddParts(GetExports()); } -- cgit v1.2.3 From f176307e591dc8cd4fd1dabe1ebc5e22fba26d51 Mon Sep 17 00:00:00 2001 From: Luke Pulverenti Date: Tue, 24 Sep 2013 15:54:42 -0400 Subject: support multiple remote control outputs --- MediaBrowser.Api/ApiEntryPoint.cs | 48 ++++- .../AuthorizationRequestFilterAttribute.cs | 181 +++++++++++++++++ MediaBrowser.Api/BaseApiService.cs | 147 +------------- MediaBrowser.Api/MediaBrowser.Api.csproj | 7 +- MediaBrowser.Api/Playback/BaseStreamingService.cs | 2 +- MediaBrowser.Api/Playback/Hls/AudioHlsService.cs | 36 ---- MediaBrowser.Api/Playback/Hls/BaseHlsService.cs | 24 --- .../Playback/Hls/HlsSegmentResponseFilter.cs | 53 +++++ MediaBrowser.Api/Playback/Hls/HlsSegmentService.cs | 147 ++++++++++++++ MediaBrowser.Api/Playback/Hls/VideoHlsService.cs | 67 +------ MediaBrowser.Api/SessionsService.cs | 218 +++------------------ MediaBrowser.Api/UserLibrary/UserLibraryService.cs | 23 +-- MediaBrowser.Controller/Session/ISessionManager.cs | 36 ++++ .../Session/ISessionRemoteController.cs | 36 ++++ .../Session/SessionManager.cs | 64 ++++++ .../Session/WebSocketController.cs | 94 ++++++--- 16 files changed, 677 insertions(+), 506 deletions(-) create mode 100644 MediaBrowser.Api/AuthorizationRequestFilterAttribute.cs create mode 100644 MediaBrowser.Api/Playback/Hls/HlsSegmentResponseFilter.cs create mode 100644 MediaBrowser.Api/Playback/Hls/HlsSegmentService.cs (limited to 'MediaBrowser.Controller') diff --git a/MediaBrowser.Api/ApiEntryPoint.cs b/MediaBrowser.Api/ApiEntryPoint.cs index 52707c3c6..273d9a7a9 100644 --- a/MediaBrowser.Api/ApiEntryPoint.cs +++ b/MediaBrowser.Api/ApiEntryPoint.cs @@ -62,7 +62,7 @@ namespace MediaBrowser.Api { var jobCount = _activeTranscodingJobs.Count; - Parallel.ForEach(_activeTranscodingJobs, OnTranscodeKillTimerStopped); + Parallel.ForEach(_activeTranscodingJobs, KillTranscodingJob); // Try to allow for some time to kill the ffmpeg processes and delete the partial stream files if (jobCount > 0) @@ -84,7 +84,8 @@ namespace MediaBrowser.Api /// The process. /// if set to true [is video]. /// The start time ticks. - public void OnTranscodeBeginning(string path, TranscodingJobType type, Process process, bool isVideo, long? startTimeTicks) + /// The source path. + public void OnTranscodeBeginning(string path, TranscodingJobType type, Process process, bool isVideo, long? startTimeTicks, string sourcePath) { lock (_activeTranscodingJobs) { @@ -95,7 +96,8 @@ namespace MediaBrowser.Api Process = process, ActiveRequestCount = 1, IsVideo = isVideo, - StartTimeTicks = startTimeTicks + StartTimeTicks = startTimeTicks, + SourcePath = sourcePath }); } } @@ -196,10 +198,47 @@ namespace MediaBrowser.Api /// Called when [transcode kill timer stopped]. /// /// The state. - private async void OnTranscodeKillTimerStopped(object state) + private void OnTranscodeKillTimerStopped(object state) { var job = (TranscodingJob)state; + KillTranscodingJob(job); + } + + /// + /// Kills the single transcoding job. + /// + /// The source path. + internal void KillSingleTranscodingJob(string sourcePath) + { + if (string.IsNullOrEmpty(sourcePath)) + { + throw new ArgumentNullException("sourcePath"); + } + + var jobs = new List(); + + lock (_activeTranscodingJobs) + { + // This is really only needed for HLS. + // Progressive streams can stop on their own reliably + jobs.AddRange(_activeTranscodingJobs.Where(i => string.Equals(sourcePath, i.SourcePath) && i.Type == TranscodingJobType.Hls)); + } + + // This method of killing is a bit of a shortcut, but it saves clients from having to send a request just for that + // But we can only kill if there's one active job. If there are more we won't know which one to stop + if (jobs.Count == 1) + { + KillTranscodingJob(jobs.First()); + } + } + + /// + /// Kills the transcoding job. + /// + /// The job. + private async void KillTranscodingJob(TranscodingJob job) + { lock (_activeTranscodingJobs) { _activeTranscodingJobs.Remove(job); @@ -373,6 +412,7 @@ namespace MediaBrowser.Api public bool IsVideo { get; set; } public long? StartTimeTicks { get; set; } + public string SourcePath { get; set; } } /// diff --git a/MediaBrowser.Api/AuthorizationRequestFilterAttribute.cs b/MediaBrowser.Api/AuthorizationRequestFilterAttribute.cs new file mode 100644 index 000000000..d225bdd99 --- /dev/null +++ b/MediaBrowser.Api/AuthorizationRequestFilterAttribute.cs @@ -0,0 +1,181 @@ +using MediaBrowser.Controller.Entities; +using MediaBrowser.Controller.Library; +using MediaBrowser.Controller.Session; +using MediaBrowser.Model.Logging; +using ServiceStack.Common.Web; +using ServiceStack.ServiceHost; +using System; +using System.Collections.Generic; + +namespace MediaBrowser.Api +{ + public class AuthorizationRequestFilterAttribute : Attribute, IHasRequestFilter + { + //This property will be resolved by the IoC container + /// + /// Gets or sets the user manager. + /// + /// The user manager. + public IUserManager UserManager { get; set; } + + public ISessionManager SessionManager { get; set; } + + /// + /// Gets or sets the logger. + /// + /// The logger. + public ILogger Logger { get; set; } + + /// + /// The request filter is executed before the service. + /// + /// The http request wrapper + /// The http response wrapper + /// The request DTO + public void RequestFilter(IHttpRequest request, IHttpResponse response, object requestDto) + { + //This code is executed before the service + + var auth = GetAuthorization(request); + + if (auth != null) + { + User user = null; + + if (auth.ContainsKey("UserId")) + { + var userId = auth["UserId"]; + + if (!string.IsNullOrEmpty(userId)) + { + user = UserManager.GetUserById(new Guid(userId)); + } + } + + string deviceId; + string device; + string client; + string version; + + auth.TryGetValue("DeviceId", out deviceId); + auth.TryGetValue("Device", out device); + auth.TryGetValue("Client", out client); + auth.TryGetValue("Version", out version); + + if (!string.IsNullOrEmpty(client) && !string.IsNullOrEmpty(deviceId) && !string.IsNullOrEmpty(device) && !string.IsNullOrEmpty(version)) + { + SessionManager.LogConnectionActivity(client, version, deviceId, device, user); + } + } + } + + /// + /// Gets the auth. + /// + /// The HTTP req. + /// Dictionary{System.StringSystem.String}. + public static Dictionary GetAuthorization(IHttpRequest httpReq) + { + var auth = httpReq.Headers[HttpHeaders.Authorization]; + + return GetAuthorization(auth); + } + + /// + /// Gets the authorization. + /// + /// The HTTP req. + /// Dictionary{System.StringSystem.String}. + public static AuthorizationInfo GetAuthorization(IRequestContext httpReq) + { + var header = httpReq.GetHeader("Authorization"); + + var auth = GetAuthorization(header); + + string userId; + string deviceId; + string device; + string client; + string version; + + auth.TryGetValue("UserId", out userId); + auth.TryGetValue("DeviceId", out deviceId); + auth.TryGetValue("Device", out device); + auth.TryGetValue("Client", out client); + auth.TryGetValue("Version", out version); + + return new AuthorizationInfo + { + Client = client, + Device = device, + DeviceId = deviceId, + UserId = userId, + Version = version + }; + } + + /// + /// Gets the authorization. + /// + /// The authorization header. + /// Dictionary{System.StringSystem.String}. + private static Dictionary GetAuthorization(string authorizationHeader) + { + if (authorizationHeader == null) return null; + + var parts = authorizationHeader.Split(' '); + + // There should be at least to parts + if (parts.Length < 2) return null; + + // It has to be a digest request + if (!string.Equals(parts[0], "MediaBrowser", StringComparison.OrdinalIgnoreCase)) + { + return null; + } + + // Remove uptil the first space + authorizationHeader = authorizationHeader.Substring(authorizationHeader.IndexOf(' ')); + parts = authorizationHeader.Split(','); + + var result = new Dictionary(StringComparer.OrdinalIgnoreCase); + + foreach (var item in parts) + { + var param = item.Trim().Split(new[] { '=' }, 2); + result.Add(param[0], param[1].Trim(new[] { '"' })); + } + + return result; + } + + /// + /// A new shallow copy of this filter is used on every request. + /// + /// IHasRequestFilter. + public IHasRequestFilter Copy() + { + return this; + } + + /// + /// Order in which Request Filters are executed. + /// <0 Executed before global request filters + /// >0 Executed after global request filters + /// + /// The priority. + public int Priority + { + get { return 0; } + } + } + + public class AuthorizationInfo + { + public string UserId; + public string DeviceId; + public string Device; + public string Client; + public string Version; + } +} diff --git a/MediaBrowser.Api/BaseApiService.cs b/MediaBrowser.Api/BaseApiService.cs index b3f5027e0..069bc0fe1 100644 --- a/MediaBrowser.Api/BaseApiService.cs +++ b/MediaBrowser.Api/BaseApiService.cs @@ -2,9 +2,7 @@ using MediaBrowser.Controller.Entities; using MediaBrowser.Controller.Entities.Audio; using MediaBrowser.Controller.Library; -using MediaBrowser.Controller.Session; using MediaBrowser.Model.Logging; -using ServiceStack.Common.Web; using ServiceStack.ServiceHost; using System; using System.Collections.Generic; @@ -15,7 +13,7 @@ namespace MediaBrowser.Api /// /// Class BaseApiService /// - [RequestFilter] + [AuthorizationRequestFilter] public class BaseApiService : IHasResultFactory, IRestfulService { /// @@ -308,147 +306,4 @@ namespace MediaBrowser.Api return item; } } - - /// - /// Class RequestFilterAttribute - /// - public class RequestFilterAttribute : Attribute, IHasRequestFilter - { - //This property will be resolved by the IoC container - /// - /// Gets or sets the user manager. - /// - /// The user manager. - public IUserManager UserManager { get; set; } - - public ISessionManager SessionManager { get; set; } - - /// - /// Gets or sets the logger. - /// - /// The logger. - public ILogger Logger { get; set; } - - /// - /// The request filter is executed before the service. - /// - /// The http request wrapper - /// The http response wrapper - /// The request DTO - public void RequestFilter(IHttpRequest request, IHttpResponse response, object requestDto) - { - //This code is executed before the service - - var auth = GetAuthorization(request); - - if (auth != null) - { - User user = null; - - if (auth.ContainsKey("UserId")) - { - var userId = auth["UserId"]; - - if (!string.IsNullOrEmpty(userId)) - { - user = UserManager.GetUserById(new Guid(userId)); - } - } - - string deviceId; - string device; - string client; - string version; - - auth.TryGetValue("DeviceId", out deviceId); - auth.TryGetValue("Device", out device); - auth.TryGetValue("Client", out client); - auth.TryGetValue("Version", out version); - - if (!string.IsNullOrEmpty(client) && !string.IsNullOrEmpty(deviceId) && !string.IsNullOrEmpty(device) && !string.IsNullOrEmpty(version)) - { - SessionManager.LogConnectionActivity(client, version, deviceId, device, user); - } - } - } - - /// - /// Gets the auth. - /// - /// The HTTP req. - /// Dictionary{System.StringSystem.String}. - public static Dictionary GetAuthorization(IHttpRequest httpReq) - { - var auth = httpReq.Headers[HttpHeaders.Authorization]; - - return GetAuthorization(auth); - } - - /// - /// Gets the authorization. - /// - /// The HTTP req. - /// Dictionary{System.StringSystem.String}. - public static Dictionary GetAuthorization(IRequestContext httpReq) - { - var auth = httpReq.GetHeader("Authorization"); - - return GetAuthorization(auth); - } - - /// - /// Gets the authorization. - /// - /// The authorization header. - /// Dictionary{System.StringSystem.String}. - private static Dictionary GetAuthorization(string authorizationHeader) - { - if (authorizationHeader == null) return null; - - var parts = authorizationHeader.Split(' '); - - // There should be at least to parts - if (parts.Length < 2) return null; - - // It has to be a digest request - if (!string.Equals(parts[0], "MediaBrowser", StringComparison.OrdinalIgnoreCase)) - { - return null; - } - - // Remove uptil the first space - authorizationHeader = authorizationHeader.Substring(authorizationHeader.IndexOf(' ')); - parts = authorizationHeader.Split(','); - - var result = new Dictionary(StringComparer.OrdinalIgnoreCase); - - foreach (var item in parts) - { - var param = item.Trim().Split(new[] { '=' }, 2); - result.Add(param[0], param[1].Trim(new[] { '"' })); - } - - return result; - } - - /// - /// A new shallow copy of this filter is used on every request. - /// - /// IHasRequestFilter. - public IHasRequestFilter Copy() - { - return this; - } - - /// - /// Order in which Request Filters are executed. - /// <0 Executed before global request filters - /// >0 Executed after global request filters - /// - /// The priority. - public int Priority - { - get { return 0; } - } - } } diff --git a/MediaBrowser.Api/MediaBrowser.Api.csproj b/MediaBrowser.Api/MediaBrowser.Api.csproj index c7cca812f..995b5cdf1 100644 --- a/MediaBrowser.Api/MediaBrowser.Api.csproj +++ b/MediaBrowser.Api/MediaBrowser.Api.csproj @@ -70,6 +70,7 @@ + @@ -88,6 +89,8 @@ + + @@ -143,7 +146,9 @@ - + + + diff --git a/MediaBrowser.Api/Playback/BaseStreamingService.cs b/MediaBrowser.Api/Playback/BaseStreamingService.cs index e31a112d5..c782c243d 100644 --- a/MediaBrowser.Api/Playback/BaseStreamingService.cs +++ b/MediaBrowser.Api/Playback/BaseStreamingService.cs @@ -613,7 +613,7 @@ namespace MediaBrowser.Api.Playback EnableRaisingEvents = true }; - ApiEntryPoint.Instance.OnTranscodeBeginning(outputPath, TranscodingJobType, process, video != null, state.Request.StartTimeTicks); + ApiEntryPoint.Instance.OnTranscodeBeginning(outputPath, TranscodingJobType, process, video != null, state.Request.StartTimeTicks, state.Item.Path); Logger.Info(process.StartInfo.FileName + " " + process.StartInfo.Arguments); diff --git a/MediaBrowser.Api/Playback/Hls/AudioHlsService.cs b/MediaBrowser.Api/Playback/Hls/AudioHlsService.cs index d7ee73a9e..6e36ba0ad 100644 --- a/MediaBrowser.Api/Playback/Hls/AudioHlsService.cs +++ b/MediaBrowser.Api/Playback/Hls/AudioHlsService.cs @@ -6,7 +6,6 @@ using MediaBrowser.Model.Dto; using MediaBrowser.Model.IO; using ServiceStack.ServiceHost; using System; -using System.IO; namespace MediaBrowser.Api.Playback.Hls { @@ -20,27 +19,6 @@ namespace MediaBrowser.Api.Playback.Hls } - /// - /// Class GetHlsAudioSegment - /// - [Route("/Audio/{Id}/hls/{SegmentId}/stream.mp3", "GET")] - [Route("/Audio/{Id}/hls/{SegmentId}/stream.aac", "GET")] - [Api(Description = "Gets an Http live streaming segment file. Internal use only.")] - public class GetHlsAudioSegment - { - /// - /// Gets or sets the id. - /// - /// The id. - public string Id { get; set; } - - /// - /// Gets or sets the segment id. - /// - /// The segment id. - public string SegmentId { get; set; } - } - /// /// Class AudioHlsService /// @@ -59,20 +37,6 @@ namespace MediaBrowser.Api.Playback.Hls { } - /// - /// Gets the specified request. - /// - /// The request. - /// System.Object. - public object Get(GetHlsAudioSegment request) - { - var file = request.SegmentId + Path.GetExtension(RequestContext.PathInfo); - - file = Path.Combine(ApplicationPaths.EncodedMediaCachePath, file); - - return ResultFactory.GetStaticFileResult(RequestContext, file, FileShare.ReadWrite); - } - /// /// Gets the specified request. /// diff --git a/MediaBrowser.Api/Playback/Hls/BaseHlsService.cs b/MediaBrowser.Api/Playback/Hls/BaseHlsService.cs index e680546b0..05441bba7 100644 --- a/MediaBrowser.Api/Playback/Hls/BaseHlsService.cs +++ b/MediaBrowser.Api/Playback/Hls/BaseHlsService.cs @@ -10,7 +10,6 @@ using MediaBrowser.Model.IO; using System; using System.Collections.Generic; using System.IO; -using System.Linq; using System.Text; using System.Threading.Tasks; @@ -213,29 +212,6 @@ namespace MediaBrowser.Api.Playback.Hls return count; } - protected void ExtendHlsTimer(string itemId, string playlistId) - { - var normalizedPlaylistId = playlistId.Replace("-low", string.Empty); - - foreach (var playlist in Directory.EnumerateFiles(ApplicationPaths.EncodedMediaCachePath, "*.m3u8") - .Where(i => i.IndexOf(normalizedPlaylistId, StringComparison.OrdinalIgnoreCase) != -1) - .ToList()) - { - ApiEntryPoint.Instance.OnTranscodeBeginRequest(playlist, TranscodingJobType.Hls); - - // Avoid implicitly captured closure - var playlist1 = playlist; - - Task.Run(async () => - { - // This is an arbitrary time period corresponding to when the request completes. - await Task.Delay(30000).ConfigureAwait(false); - - ApiEntryPoint.Instance.OnTranscodeEndRequest(playlist1, TranscodingJobType.Hls); - }); - } - } - /// /// Gets the command line arguments. /// diff --git a/MediaBrowser.Api/Playback/Hls/HlsSegmentResponseFilter.cs b/MediaBrowser.Api/Playback/Hls/HlsSegmentResponseFilter.cs new file mode 100644 index 000000000..44996c99f --- /dev/null +++ b/MediaBrowser.Api/Playback/Hls/HlsSegmentResponseFilter.cs @@ -0,0 +1,53 @@ +using MediaBrowser.Controller; +using MediaBrowser.Model.Logging; +using ServiceStack.ServiceHost; +using ServiceStack.Text.Controller; +using System; +using System.IO; +using System.Linq; + +namespace MediaBrowser.Api.Playback.Hls +{ + public class HlsSegmentResponseFilter : Attribute, IHasResponseFilter + { + public ILogger Logger { get; set; } + public IServerApplicationPaths ApplicationPaths { get; set; } + + public void ResponseFilter(IHttpRequest req, IHttpResponse res, object response) + { + var pathInfo = PathInfo.Parse(req.PathInfo); + var itemId = pathInfo.GetArgumentValue(1); + var playlistId = pathInfo.GetArgumentValue(3); + + OnEndRequest(itemId, playlistId); + } + + public IHasResponseFilter Copy() + { + return this; + } + + public int Priority + { + get { return -1; } + } + + /// + /// Called when [end request]. + /// + /// The item id. + /// The playlist id. + protected void OnEndRequest(string itemId, string playlistId) + { + Logger.Info("OnEndRequest " + playlistId); + var normalizedPlaylistId = playlistId.Replace("-low", string.Empty); + + foreach (var playlist in Directory.EnumerateFiles(ApplicationPaths.EncodedMediaCachePath, "*.m3u8") + .Where(i => i.IndexOf(normalizedPlaylistId, StringComparison.OrdinalIgnoreCase) != -1) + .ToList()) + { + ApiEntryPoint.Instance.OnTranscodeEndRequest(playlist, TranscodingJobType.Hls); + } + } + } +} diff --git a/MediaBrowser.Api/Playback/Hls/HlsSegmentService.cs b/MediaBrowser.Api/Playback/Hls/HlsSegmentService.cs new file mode 100644 index 000000000..f1fa86f78 --- /dev/null +++ b/MediaBrowser.Api/Playback/Hls/HlsSegmentService.cs @@ -0,0 +1,147 @@ +using MediaBrowser.Controller; +using ServiceStack.ServiceHost; +using System; +using System.IO; +using System.Linq; +using System.Threading.Tasks; + +namespace MediaBrowser.Api.Playback.Hls +{ + /// + /// Class GetHlsAudioSegment + /// + [Route("/Audio/{Id}/hls/{SegmentId}/stream.mp3", "GET")] + [Route("/Audio/{Id}/hls/{SegmentId}/stream.aac", "GET")] + [Api(Description = "Gets an Http live streaming segment file. Internal use only.")] + public class GetHlsAudioSegment + { + /// + /// Gets or sets the id. + /// + /// The id. + public string Id { get; set; } + + /// + /// Gets or sets the segment id. + /// + /// The segment id. + public string SegmentId { get; set; } + } + + /// + /// Class GetHlsVideoSegment + /// + [Route("/Videos/{Id}/hls/{PlaylistId}/{SegmentId}.ts", "GET")] + [Api(Description = "Gets an Http live streaming segment file. Internal use only.")] + public class GetHlsVideoSegment + { + /// + /// Gets or sets the id. + /// + /// The id. + public string Id { get; set; } + + public string PlaylistId { get; set; } + + /// + /// Gets or sets the segment id. + /// + /// The segment id. + public string SegmentId { get; set; } + } + + /// + /// Class GetHlsVideoSegment + /// + [Route("/Videos/{Id}/hls/{PlaylistId}/stream.m3u8", "GET")] + [Api(Description = "Gets an Http live streaming segment file. Internal use only.")] + public class GetHlsPlaylist + { + /// + /// Gets or sets the id. + /// + /// The id. + public string Id { get; set; } + + public string PlaylistId { get; set; } + } + + public class HlsSegmentService : BaseApiService + { + private readonly IServerApplicationPaths _appPaths; + + public HlsSegmentService(IServerApplicationPaths appPaths) + { + _appPaths = appPaths; + } + + public object Get(GetHlsPlaylist request) + { + OnBeginRequest(request.PlaylistId); + + var file = request.PlaylistId + Path.GetExtension(RequestContext.PathInfo); + + file = Path.Combine(_appPaths.EncodedMediaCachePath, file); + + return ResultFactory.GetStaticFileResult(RequestContext, file, FileShare.ReadWrite); + } + + /// + /// Gets the specified request. + /// + /// The request. + /// System.Object. + public object Get(GetHlsVideoSegment request) + { + var file = request.SegmentId + Path.GetExtension(RequestContext.PathInfo); + + file = Path.Combine(_appPaths.EncodedMediaCachePath, file); + + OnBeginRequest(request.PlaylistId); + + return ResultFactory.GetStaticFileResult(RequestContext, file); + } + + /// + /// Gets the specified request. + /// + /// The request. + /// System.Object. + public object Get(GetHlsAudioSegment request) + { + var file = request.SegmentId + Path.GetExtension(RequestContext.PathInfo); + + file = Path.Combine(_appPaths.EncodedMediaCachePath, file); + + return ResultFactory.GetStaticFileResult(RequestContext, file, FileShare.ReadWrite); + } + + /// + /// Called when [begin request]. + /// + /// The playlist id. + protected void OnBeginRequest(string playlistId) + { + var normalizedPlaylistId = playlistId.Replace("-low", string.Empty); + + foreach (var playlist in Directory.EnumerateFiles(_appPaths.EncodedMediaCachePath, "*.m3u8") + .Where(i => i.IndexOf(normalizedPlaylistId, StringComparison.OrdinalIgnoreCase) != -1) + .ToList()) + { + ExtendPlaylistTimer(playlist); + } + } + + private void ExtendPlaylistTimer(string playlist) + { + ApiEntryPoint.Instance.OnTranscodeBeginRequest(playlist, TranscodingJobType.Hls); + + Task.Run(async () => + { + await Task.Delay(20000).ConfigureAwait(false); + + ApiEntryPoint.Instance.OnTranscodeEndRequest(playlist, TranscodingJobType.Hls); + }); + } + } +} diff --git a/MediaBrowser.Api/Playback/Hls/VideoHlsService.cs b/MediaBrowser.Api/Playback/Hls/VideoHlsService.cs index 901b27688..4694b68a1 100644 --- a/MediaBrowser.Api/Playback/Hls/VideoHlsService.cs +++ b/MediaBrowser.Api/Playback/Hls/VideoHlsService.cs @@ -5,7 +5,6 @@ using MediaBrowser.Controller.Library; using MediaBrowser.Model.IO; using ServiceStack.ServiceHost; using System; -using System.IO; namespace MediaBrowser.Api.Playback.Hls { @@ -31,44 +30,6 @@ namespace MediaBrowser.Api.Playback.Hls } } - /// - /// Class GetHlsVideoSegment - /// - [Route("/Videos/{Id}/hls/{PlaylistId}/{SegmentId}.ts", "GET")] - [Api(Description = "Gets an Http live streaming segment file. Internal use only.")] - public class GetHlsVideoSegment - { - /// - /// Gets or sets the id. - /// - /// The id. - public string Id { get; set; } - - public string PlaylistId { get; set; } - - /// - /// Gets or sets the segment id. - /// - /// The segment id. - public string SegmentId { get; set; } - } - - /// - /// Class GetHlsVideoSegment - /// - [Route("/Videos/{Id}/hls/{PlaylistId}/stream.m3u8", "GET")] - [Api(Description = "Gets an Http live streaming segment file. Internal use only.")] - public class GetHlsPlaylist - { - /// - /// Gets or sets the id. - /// - /// The id. - public string Id { get; set; } - - public string PlaylistId { get; set; } - } - /// /// Class VideoHlsService /// @@ -82,38 +43,12 @@ namespace MediaBrowser.Api.Playback.Hls /// The library manager. /// The iso manager. /// The media encoder. + /// The dto service. public VideoHlsService(IServerApplicationPaths appPaths, IUserManager userManager, ILibraryManager libraryManager, IIsoManager isoManager, IMediaEncoder mediaEncoder, IDtoService dtoService) : base(appPaths, userManager, libraryManager, isoManager, mediaEncoder, dtoService) { } - /// - /// Gets the specified request. - /// - /// The request. - /// System.Object. - public object Get(GetHlsVideoSegment request) - { - ExtendHlsTimer(request.Id, request.PlaylistId); - - var file = request.SegmentId + Path.GetExtension(RequestContext.PathInfo); - - file = Path.Combine(ApplicationPaths.EncodedMediaCachePath, file); - - return ResultFactory.GetStaticFileResult(RequestContext, file); - } - - public object Get(GetHlsPlaylist request) - { - ExtendHlsTimer(request.Id, request.PlaylistId); - - var file = request.PlaylistId + Path.GetExtension(RequestContext.PathInfo); - - file = Path.Combine(ApplicationPaths.EncodedMediaCachePath, file); - - return ResultFactory.GetStaticFileResult(RequestContext, file, FileShare.ReadWrite); - } - /// /// Gets the specified request. /// diff --git a/MediaBrowser.Api/SessionsService.cs b/MediaBrowser.Api/SessionsService.cs index b93b5326e..5888d9fba 100644 --- a/MediaBrowser.Api/SessionsService.cs +++ b/MediaBrowser.Api/SessionsService.cs @@ -1,7 +1,5 @@ -using MediaBrowser.Common.Extensions; -using MediaBrowser.Controller.Dto; +using MediaBrowser.Controller.Dto; using MediaBrowser.Controller.Session; -using MediaBrowser.Model.Net; using MediaBrowser.Model.Session; using ServiceStack.ServiceHost; using System; @@ -189,6 +187,7 @@ namespace MediaBrowser.Api /// Initializes a new instance of the class. /// /// The session manager. + /// The dto service. public SessionsService(ISessionManager sessionManager, IDtoService dtoService) { _sessionManager = sessionManager; @@ -214,52 +213,15 @@ namespace MediaBrowser.Api public void Post(SendPlaystateCommand request) { - var task = SendPlaystateCommand(request); - - Task.WaitAll(task); - } - - private async Task SendPlaystateCommand(SendPlaystateCommand request) - { - var session = _sessionManager.Sessions.FirstOrDefault(i => i.Id == request.Id); - - if (session == null) + var command = new PlaystateRequest { - throw new ResourceNotFoundException(string.Format("Session {0} not found.", request.Id)); - } + Command = request.Command, + SeekPositionTicks = request.SeekPositionTicks + }; - if (!session.SupportsRemoteControl) - { - throw new ArgumentException(string.Format("Session {0} does not support remote control.", session.Id)); - } + var task = _sessionManager.SendPlaystateCommand(request.Id, command, CancellationToken.None); - var socket = session.WebSockets.OrderByDescending(i => i.LastActivityDate).FirstOrDefault(i => i.State == WebSocketState.Open); - - if (socket != null) - { - try - { - await socket.SendAsync(new WebSocketMessage - { - MessageType = "Playstate", - - Data = new PlaystateRequest - { - Command = request.Command, - SeekPositionTicks = request.SeekPositionTicks - } - - }, CancellationToken.None).ConfigureAwait(false); - } - catch (Exception ex) - { - Logger.ErrorException("Error sending web socket message", ex); - } - } - else - { - throw new InvalidOperationException("The requested session does not have an open web socket."); - } + Task.WaitAll(task); } /// @@ -268,55 +230,17 @@ namespace MediaBrowser.Api /// The request. public void Post(BrowseTo request) { - var task = BrowseTo(request); - - Task.WaitAll(task); - } - - /// - /// Browses to. - /// - /// The request. - /// Task. - /// - /// - /// The requested session does not have an open web socket. - private async Task BrowseTo(BrowseTo request) - { - var session = _sessionManager.Sessions.FirstOrDefault(i => i.Id == request.Id); - - if (session == null) - { - throw new ResourceNotFoundException(string.Format("Session {0} not found.", request.Id)); - } - - if (!session.SupportsRemoteControl) + var command = new BrowseRequest { - throw new ArgumentException(string.Format("Session {0} does not support remote control.", session.Id)); - } + Context = request.Context, + ItemId = request.ItemId, + ItemName = request.ItemName, + ItemType = request.ItemType + }; - var socket = session.WebSockets.OrderByDescending(i => i.LastActivityDate).FirstOrDefault(i => i.State == WebSocketState.Open); + var task = _sessionManager.SendBrowseCommand(request.Id, command, CancellationToken.None); - if (socket != null) - { - try - { - await socket.SendAsync(new WebSocketMessage - { - MessageType = "Browse", - Data = request - - }, CancellationToken.None).ConfigureAwait(false); - } - catch (Exception ex) - { - Logger.ErrorException("Error sending web socket message", ex); - } - } - else - { - throw new InvalidOperationException("The requested session does not have an open web socket."); - } + Task.WaitAll(task); } /// @@ -336,53 +260,16 @@ namespace MediaBrowser.Api /// The request. public void Post(SendMessageCommand request) { - var task = SendMessageCommand(request); - - Task.WaitAll(task); - } - - private async Task SendMessageCommand(SendMessageCommand request) - { - var session = _sessionManager.Sessions.FirstOrDefault(i => i.Id == request.Id); - - if (session == null) - { - throw new ResourceNotFoundException(string.Format("Session {0} not found.", request.Id)); - } - - if (!session.SupportsRemoteControl) + var command = new MessageCommand { - throw new ArgumentException(string.Format("Session {0} does not support remote control.", session.Id)); - } + Header = string.IsNullOrEmpty(request.Header) ? "Message from Server" : request.Header, + TimeoutMs = request.TimeoutMs, + Text = request.Text + }; - var socket = session.WebSockets.OrderByDescending(i => i.LastActivityDate).FirstOrDefault(i => i.State == WebSocketState.Open); + var task = _sessionManager.SendMessageCommand(request.Id, command, CancellationToken.None); - if (socket != null) - { - try - { - await socket.SendAsync(new WebSocketMessage - { - MessageType = "MessageCommand", - - Data = new MessageCommand - { - Header = string.IsNullOrEmpty(request.Header) ? "Message from Server" : request.Header, - TimeoutMs = request.TimeoutMs, - Text = request.Text - } - - }, CancellationToken.None).ConfigureAwait(false); - } - catch (Exception ex) - { - Logger.ErrorException("Error sending web socket message", ex); - } - } - else - { - throw new InvalidOperationException("The requested session does not have an open web socket."); - } + Task.WaitAll(task); } /// @@ -391,62 +278,17 @@ namespace MediaBrowser.Api /// The request. public void Post(Play request) { - var task = Play(request); - - Task.WaitAll(task); - } - - /// - /// Plays the specified request. - /// - /// The request. - /// Task. - /// - /// - /// The requested session does not have an open web socket. - private async Task Play(Play request) - { - var session = _sessionManager.Sessions.FirstOrDefault(i => i.Id == request.Id); - - if (session == null) + var command = new PlayRequest { - throw new ResourceNotFoundException(string.Format("Session {0} not found.", request.Id)); - } + ItemIds = request.ItemIds.Split(',').ToArray(), - if (!session.SupportsRemoteControl) - { - throw new ArgumentException(string.Format("Session {0} does not support remote control.", session.Id)); - } + PlayCommand = request.PlayCommand, + StartPositionTicks = request.StartPositionTicks + }; - var socket = session.WebSockets.OrderByDescending(i => i.LastActivityDate).FirstOrDefault(i => i.State == WebSocketState.Open); + var task = _sessionManager.SendPlayCommand(request.Id, command, CancellationToken.None); - if (socket != null) - { - try - { - await socket.SendAsync(new WebSocketMessage - { - MessageType = "Play", - - Data = new PlayRequest - { - ItemIds = request.ItemIds.Split(',').ToArray(), - - PlayCommand = request.PlayCommand, - StartPositionTicks = request.StartPositionTicks - } - - }, CancellationToken.None).ConfigureAwait(false); - } - catch (Exception ex) - { - Logger.ErrorException("Error sending web socket message", ex); - } - } - else - { - throw new InvalidOperationException("The requested session does not have an open web socket."); - } + Task.WaitAll(task); } } } diff --git a/MediaBrowser.Api/UserLibrary/UserLibraryService.cs b/MediaBrowser.Api/UserLibrary/UserLibraryService.cs index 9085a3ecf..abd42910f 100644 --- a/MediaBrowser.Api/UserLibrary/UserLibraryService.cs +++ b/MediaBrowser.Api/UserLibrary/UserLibraryService.cs @@ -663,19 +663,11 @@ namespace MediaBrowser.Api.UserLibrary private SessionInfo GetSession() { - var auth = RequestFilterAttribute.GetAuthorization(RequestContext); + var auth = AuthorizationRequestFilterAttribute.GetAuthorization(RequestContext); - string deviceId; - string client; - string version; - - auth.TryGetValue("DeviceId", out deviceId); - auth.TryGetValue("Client", out client); - auth.TryGetValue("Version", out version); - - return _sessionManager.Sessions.First(i => string.Equals(i.DeviceId, deviceId) && - string.Equals(i.Client, client) && - string.Equals(i.ApplicationVersion, version)); + return _sessionManager.Sessions.First(i => string.Equals(i.DeviceId, auth.DeviceId) && + string.Equals(i.Client, auth.Client) && + string.Equals(i.ApplicationVersion, auth.Version)); } /// @@ -726,7 +718,12 @@ namespace MediaBrowser.Api.UserLibrary var item = _dtoService.GetItemByDtoId(request.Id, user.Id); - var task = _sessionManager.OnPlaybackStopped(item, request.PositionTicks, GetSession().Id); + // Kill the encoding + ApiEntryPoint.Instance.KillSingleTranscodingJob(item.Path); + + var session = GetSession(); + + var task = _sessionManager.OnPlaybackStopped(item, request.PositionTicks, session.Id); Task.WaitAll(task); } diff --git a/MediaBrowser.Controller/Session/ISessionManager.cs b/MediaBrowser.Controller/Session/ISessionManager.cs index f8f7ded2b..0932ee52d 100644 --- a/MediaBrowser.Controller/Session/ISessionManager.cs +++ b/MediaBrowser.Controller/Session/ISessionManager.cs @@ -89,5 +89,41 @@ namespace MediaBrowser.Controller.Session /// The cancellation token. /// Task. Task SendSystemCommand(Guid sessionId, SystemCommand command, CancellationToken cancellationToken); + + /// + /// Sends the message command. + /// + /// The session id. + /// The command. + /// The cancellation token. + /// Task. + Task SendMessageCommand(Guid sessionId, MessageCommand command, CancellationToken cancellationToken); + + /// + /// Sends the play command. + /// + /// The session id. + /// The command. + /// The cancellation token. + /// Task. + Task SendPlayCommand(Guid sessionId, PlayRequest command, CancellationToken cancellationToken); + + /// + /// Sends the browse command. + /// + /// The session id. + /// The command. + /// The cancellation token. + /// Task. + Task SendBrowseCommand(Guid sessionId, BrowseRequest command, CancellationToken cancellationToken); + + /// + /// Sends the playstate command. + /// + /// The session id. + /// The command. + /// The cancellation token. + /// Task. + Task SendPlaystateCommand(Guid sessionId, PlaystateRequest command, CancellationToken cancellationToken); } } \ No newline at end of file diff --git a/MediaBrowser.Controller/Session/ISessionRemoteController.cs b/MediaBrowser.Controller/Session/ISessionRemoteController.cs index 1f6faeb9c..9ba5c983d 100644 --- a/MediaBrowser.Controller/Session/ISessionRemoteController.cs +++ b/MediaBrowser.Controller/Session/ISessionRemoteController.cs @@ -21,5 +21,41 @@ namespace MediaBrowser.Controller.Session /// The cancellation token. /// Task. Task SendSystemCommand(SessionInfo session, SystemCommand command, CancellationToken cancellationToken); + + /// + /// Sends the message command. + /// + /// The session. + /// The command. + /// The cancellation token. + /// Task. + Task SendMessageCommand(SessionInfo session, MessageCommand command, CancellationToken cancellationToken); + + /// + /// Sends the play command. + /// + /// The session. + /// The command. + /// The cancellation token. + /// Task. + Task SendPlayCommand(SessionInfo session, PlayRequest command, CancellationToken cancellationToken); + + /// + /// Sends the browse command. + /// + /// The session. + /// The command. + /// The cancellation token. + /// Task. + Task SendBrowseCommand(SessionInfo session, BrowseRequest command, CancellationToken cancellationToken); + + /// + /// Sends the playstate command. + /// + /// The session. + /// The command. + /// The cancellation token. + /// Task. + Task SendPlaystateCommand(SessionInfo session, PlaystateRequest command, CancellationToken cancellationToken); } } diff --git a/MediaBrowser.Server.Implementations/Session/SessionManager.cs b/MediaBrowser.Server.Implementations/Session/SessionManager.cs index 5b0d957ae..79dfbc8a5 100644 --- a/MediaBrowser.Server.Implementations/Session/SessionManager.cs +++ b/MediaBrowser.Server.Implementations/Session/SessionManager.cs @@ -465,5 +465,69 @@ namespace MediaBrowser.Server.Implementations.Session return Task.WhenAll(tasks); } + + /// + /// Sends the message command. + /// + /// The session id. + /// The command. + /// The cancellation token. + /// Task. + public Task SendMessageCommand(Guid sessionId, MessageCommand command, CancellationToken cancellationToken) + { + var session = GetSessionForRemoteControl(sessionId); + + var tasks = GetControllers(session).Select(i => i.SendMessageCommand(session, command, cancellationToken)); + + return Task.WhenAll(tasks); + } + + /// + /// Sends the play command. + /// + /// The session id. + /// The command. + /// The cancellation token. + /// Task. + public Task SendPlayCommand(Guid sessionId, PlayRequest command, CancellationToken cancellationToken) + { + var session = GetSessionForRemoteControl(sessionId); + + var tasks = GetControllers(session).Select(i => i.SendPlayCommand(session, command, cancellationToken)); + + return Task.WhenAll(tasks); + } + + /// + /// Sends the browse command. + /// + /// The session id. + /// The command. + /// The cancellation token. + /// Task. + public Task SendBrowseCommand(Guid sessionId, BrowseRequest command, CancellationToken cancellationToken) + { + var session = GetSessionForRemoteControl(sessionId); + + var tasks = GetControllers(session).Select(i => i.SendBrowseCommand(session, command, cancellationToken)); + + return Task.WhenAll(tasks); + } + + /// + /// Sends the playstate command. + /// + /// The session id. + /// The command. + /// The cancellation token. + /// Task. + public Task SendPlaystateCommand(Guid sessionId, PlaystateRequest command, CancellationToken cancellationToken) + { + var session = GetSessionForRemoteControl(sessionId); + + var tasks = GetControllers(session).Select(i => i.SendPlaystateCommand(session, command, cancellationToken)); + + return Task.WhenAll(tasks); + } } } diff --git a/MediaBrowser.Server.Implementations/Session/WebSocketController.cs b/MediaBrowser.Server.Implementations/Session/WebSocketController.cs index daa4c7d81..6915cfc64 100644 --- a/MediaBrowser.Server.Implementations/Session/WebSocketController.cs +++ b/MediaBrowser.Server.Implementations/Session/WebSocketController.cs @@ -1,5 +1,5 @@ -using MediaBrowser.Controller.Session; -using MediaBrowser.Model.Logging; +using MediaBrowser.Common.Net; +using MediaBrowser.Controller.Session; using MediaBrowser.Model.Net; using MediaBrowser.Model.Session; using System; @@ -11,42 +11,82 @@ namespace MediaBrowser.Server.Implementations.Session { public class WebSocketController : ISessionRemoteController { - private readonly ILogger _logger; - - public WebSocketController(ILogger logger) - { - _logger = logger; - } - public bool Supports(SessionInfo session) { return session.WebSockets.Any(i => i.State == WebSocketState.Open); } - public async Task SendSystemCommand(SessionInfo session, SystemCommand command, CancellationToken cancellationToken) + private IWebSocketConnection GetSocket(SessionInfo session) { var socket = session.WebSockets.OrderByDescending(i => i.LastActivityDate).FirstOrDefault(i => i.State == WebSocketState.Open); - if (socket != null) - { - try - { - await socket.SendAsync(new WebSocketMessage - { - MessageType = "SystemCommand", - Data = command.ToString() - - }, cancellationToken).ConfigureAwait(false); - } - catch (Exception ex) - { - _logger.ErrorException("Error sending web socket message", ex); - } - } - else + + if (socket == null) { throw new InvalidOperationException("The requested session does not have an open web socket."); } + + return socket; + } + + public Task SendSystemCommand(SessionInfo session, SystemCommand command, CancellationToken cancellationToken) + { + var socket = GetSocket(session); + + return socket.SendAsync(new WebSocketMessage + { + MessageType = "SystemCommand", + Data = command.ToString() + + }, cancellationToken); + } + + public Task SendMessageCommand(SessionInfo session, MessageCommand command, CancellationToken cancellationToken) + { + var socket = GetSocket(session); + + return socket.SendAsync(new WebSocketMessage + { + MessageType = "MessageCommand", + Data = command + + }, cancellationToken); + } + + public Task SendPlayCommand(SessionInfo session, PlayRequest command, CancellationToken cancellationToken) + { + var socket = GetSocket(session); + + return socket.SendAsync(new WebSocketMessage + { + MessageType = "Play", + Data = command + + }, cancellationToken); + } + + public Task SendBrowseCommand(SessionInfo session, BrowseRequest command, CancellationToken cancellationToken) + { + var socket = GetSocket(session); + + return socket.SendAsync(new WebSocketMessage + { + MessageType = "Browse", + Data = command + + }, cancellationToken); + } + + public Task SendPlaystateCommand(SessionInfo session, PlaystateRequest command, CancellationToken cancellationToken) + { + var socket = GetSocket(session); + + return socket.SendAsync(new WebSocketMessage + { + MessageType = "Playstate", + Data = command + + }, cancellationToken); } } } -- cgit v1.2.3 From 0ab379e271afe69372806ab0e24a874d3f085456 Mon Sep 17 00:00:00 2001 From: Luke Pulverenti Date: Tue, 24 Sep 2013 17:06:21 -0400 Subject: adding mono solution --- MediaBrowser.Api/MediaBrowser.Api.csproj | 34 ++++---- .../MediaBrowser.Common.Implementations.csproj | 27 ++++--- MediaBrowser.Common/MediaBrowser.Common.csproj | 23 +++--- .../MediaBrowser.Controller.csproj | 16 ++-- MediaBrowser.Model/MediaBrowser.Model.csproj | 11 +-- MediaBrowser.Mono.sln | 68 ++++++++++++++++ MediaBrowser.Mono.userprefs | 8 ++ .../MediaBrowser.Providers.csproj | 15 ++-- .../Library/Validators/GameGenresValidator.cs | 6 +- .../Library/Validators/GenresValidator.cs | 10 +-- .../Library/Validators/MusicGenresValidator.cs | 10 +-- .../Library/Validators/StudiosValidator.cs | 8 +- .../MediaBrowser.Server.Implementations.csproj | 84 +++++++++----------- MediaBrowser.Server.Mono/MainWindow.cs | 16 ++++ .../MediaBrowser.Server.Mono.csproj | 91 ++++++++++++++++++++++ MediaBrowser.Server.Mono/Program.cs | 16 ++++ .../Properties/AssemblyInfo.cs | 22 ++++++ MediaBrowser.Server.Mono/gtk-gui/MainWindow.cs | 20 +++++ MediaBrowser.Server.Mono/gtk-gui/generated.cs | 29 +++++++ MediaBrowser.Server.Mono/gtk-gui/gui.stetic | 19 +++++ .../MediaBrowser.WebDashboard.csproj | 29 ++++--- 21 files changed, 418 insertions(+), 144 deletions(-) create mode 100644 MediaBrowser.Mono.sln create mode 100644 MediaBrowser.Mono.userprefs create mode 100644 MediaBrowser.Server.Mono/MainWindow.cs create mode 100644 MediaBrowser.Server.Mono/MediaBrowser.Server.Mono.csproj create mode 100644 MediaBrowser.Server.Mono/Program.cs create mode 100644 MediaBrowser.Server.Mono/Properties/AssemblyInfo.cs create mode 100644 MediaBrowser.Server.Mono/gtk-gui/MainWindow.cs create mode 100644 MediaBrowser.Server.Mono/gtk-gui/generated.cs create mode 100644 MediaBrowser.Server.Mono/gtk-gui/gui.stetic (limited to 'MediaBrowser.Controller') diff --git a/MediaBrowser.Api/MediaBrowser.Api.csproj b/MediaBrowser.Api/MediaBrowser.Api.csproj index 995b5cdf1..4f54b5249 100644 --- a/MediaBrowser.Api/MediaBrowser.Api.csproj +++ b/MediaBrowser.Api/MediaBrowser.Api.csproj @@ -13,6 +13,8 @@ 512 ..\ true + 10.0.0 + 2.0 true @@ -36,29 +38,25 @@ Always - - False + + + + + + + ..\packages\morelinq.1.0.16006\lib\net35\MoreLinq.dll - - False + ..\packages\ServiceStack.Common.3.9.62\lib\net35\ServiceStack.Common.dll - - False + ..\packages\ServiceStack.Common.3.9.62\lib\net35\ServiceStack.Interfaces.dll - - False + ..\packages\ServiceStack.Text.3.9.62\lib\net35\ServiceStack.Text.dll - - - - - - - + @@ -131,15 +129,15 @@ - {9142eefa-7570-41e1-bfcc-468bb571af2f} + {9142EEFA-7570-41E1-BFCC-468BB571AF2F} MediaBrowser.Common - {17e1f4e6-8abd-4fe5-9ecf-43d4b6087ba2} + {17E1F4E6-8ABD-4FE5-9ECF-43D4B6087BA2} MediaBrowser.Controller - {7eeeb4bb-f3e8-48fc-b4c5-70f0fff8329b} + {7EEEB4BB-F3E8-48FC-B4C5-70F0FFF8329B} MediaBrowser.Model diff --git a/MediaBrowser.Common.Implementations/MediaBrowser.Common.Implementations.csproj b/MediaBrowser.Common.Implementations/MediaBrowser.Common.Implementations.csproj index a96f2c354..79514b5cb 100644 --- a/MediaBrowser.Common.Implementations/MediaBrowser.Common.Implementations.csproj +++ b/MediaBrowser.Common.Implementations/MediaBrowser.Common.Implementations.csproj @@ -13,6 +13,8 @@ 512 ..\ true + 10.0.0 + 2.0 true @@ -35,18 +37,6 @@ Always - - False - ..\packages\NLog.2.0.1.2\lib\net45\NLog.dll - - - False - ..\packages\ServiceStack.Text.3.9.62\lib\net35\ServiceStack.Text.dll - - - False - ..\packages\SimpleInjector.2.3.5\lib\net40-client\SimpleInjector.dll - @@ -54,6 +44,15 @@ + + ..\packages\NLog.2.0.1.2\lib\net45\NLog.dll + + + ..\packages\ServiceStack.Text.3.9.62\lib\net35\ServiceStack.Text.dll + + + ..\packages\SimpleInjector.2.3.5\lib\net40-client\SimpleInjector.dll + @@ -88,11 +87,11 @@ - {9142eefa-7570-41e1-bfcc-468bb571af2f} + {9142EEFA-7570-41E1-BFCC-468BB571AF2F} MediaBrowser.Common - {7eeeb4bb-f3e8-48fc-b4c5-70f0fff8329b} + {7EEEB4BB-F3E8-48FC-B4C5-70F0FFF8329B} MediaBrowser.Model diff --git a/MediaBrowser.Common/MediaBrowser.Common.csproj b/MediaBrowser.Common/MediaBrowser.Common.csproj index 1611c55da..8acd1a83c 100644 --- a/MediaBrowser.Common/MediaBrowser.Common.csproj +++ b/MediaBrowser.Common/MediaBrowser.Common.csproj @@ -13,6 +13,8 @@ 512 ..\ true + 10.0.0 + 2.0 true @@ -32,26 +34,19 @@ prompt 4 - - - - - - False + + + + ..\packages\ServiceStack.Common.3.9.62\lib\net35\ServiceStack.Common.dll - - False + ..\packages\ServiceStack.Common.3.9.62\lib\net35\ServiceStack.Interfaces.dll - - False + ..\packages\ServiceStack.Text.3.9.62\lib\net35\ServiceStack.Text.dll - - - @@ -113,7 +108,7 @@ - {7eeeb4bb-f3e8-48fc-b4c5-70f0fff8329b} + {7EEEB4BB-F3E8-48FC-B4C5-70F0FFF8329B} MediaBrowser.Model diff --git a/MediaBrowser.Controller/MediaBrowser.Controller.csproj b/MediaBrowser.Controller/MediaBrowser.Controller.csproj index b5ad862be..0b27a350b 100644 --- a/MediaBrowser.Controller/MediaBrowser.Controller.csproj +++ b/MediaBrowser.Controller/MediaBrowser.Controller.csproj @@ -13,6 +13,8 @@ 512 ..\ true + 10.0.0 + 2.0 true @@ -42,6 +44,8 @@ x86 prompt MinimumRecommendedRules.ruleset + 4 + false bin\x86\Release\ @@ -51,12 +55,9 @@ x86 prompt MinimumRecommendedRules.ruleset + 4 - - False - ..\packages\morelinq.1.0.16006\lib\net35\MoreLinq.dll - @@ -66,6 +67,9 @@ + + ..\packages\morelinq.1.0.16006\lib\net35\MoreLinq.dll + @@ -174,11 +178,11 @@ - {9142eefa-7570-41e1-bfcc-468bb571af2f} + {9142EEFA-7570-41E1-BFCC-468BB571AF2F} MediaBrowser.Common - {7eeeb4bb-f3e8-48fc-b4c5-70f0fff8329b} + {7EEEB4BB-F3E8-48FC-B4C5-70F0FFF8329B} MediaBrowser.Model diff --git a/MediaBrowser.Model/MediaBrowser.Model.csproj b/MediaBrowser.Model/MediaBrowser.Model.csproj index 8fb471c2d..fa4fc2986 100644 --- a/MediaBrowser.Model/MediaBrowser.Model.csproj +++ b/MediaBrowser.Model/MediaBrowser.Model.csproj @@ -14,6 +14,8 @@ ..\ true ..\packages\Fody.1.17.0.0 + 10.0.0 + 2.0 true @@ -162,14 +164,13 @@ - - False - ..\packages\PropertyChanged.Fody.1.41.0.0\Lib\NET35\PropertyChanged.dll - False - + + ..\packages\PropertyChanged.Fody.1.41.0.0\Lib\NET35\PropertyChanged.dll + False + diff --git a/MediaBrowser.Mono.sln b/MediaBrowser.Mono.sln new file mode 100644 index 000000000..0dc78ca2a --- /dev/null +++ b/MediaBrowser.Mono.sln @@ -0,0 +1,68 @@ + +Microsoft Visual Studio Solution File, Format Version 11.00 +# Visual Studio 2010 +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MediaBrowser.Model", "MediaBrowser.Model\MediaBrowser.Model.csproj", "{7EEEB4BB-F3E8-48FC-B4C5-70F0FFF8329B}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MediaBrowser.Common", "MediaBrowser.Common\MediaBrowser.Common.csproj", "{9142EEFA-7570-41E1-BFCC-468BB571AF2F}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MediaBrowser.Common.Implementations", "MediaBrowser.Common.Implementations\MediaBrowser.Common.Implementations.csproj", "{C4D2573A-3FD3-441F-81AF-174AC4CD4E1D}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MediaBrowser.Controller", "MediaBrowser.Controller\MediaBrowser.Controller.csproj", "{17E1F4E6-8ABD-4FE5-9ECF-43D4B6087BA2}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MediaBrowser.Providers", "MediaBrowser.Providers\MediaBrowser.Providers.csproj", "{442B5058-DCAF-4263-BB6A-F21E31120A1B}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MediaBrowser.Server.Implementations", "MediaBrowser.Server.Implementations\MediaBrowser.Server.Implementations.csproj", "{2E781478-814D-4A48-9D80-BFF206441A65}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MediaBrowser.WebDashboard", "MediaBrowser.WebDashboard\MediaBrowser.WebDashboard.csproj", "{5624B7B5-B5A7-41D8-9F10-CC5611109619}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MediaBrowser.Api", "MediaBrowser.Api\MediaBrowser.Api.csproj", "{4FD51AC5-2C16-4308-A993-C3A84F3B4582}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MediaBrowser.Server.Mono", "MediaBrowser.Server.Mono\MediaBrowser.Server.Mono.csproj", "{A7FE75CD-3CB4-4E71-A5BF-5347721EC8E0}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|x86 = Debug|x86 + Release|x86 = Release|x86 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {17E1F4E6-8ABD-4FE5-9ECF-43D4B6087BA2}.Debug|x86.ActiveCfg = Debug|x86 + {17E1F4E6-8ABD-4FE5-9ECF-43D4B6087BA2}.Debug|x86.Build.0 = Debug|x86 + {17E1F4E6-8ABD-4FE5-9ECF-43D4B6087BA2}.Release|x86.ActiveCfg = Release|x86 + {17E1F4E6-8ABD-4FE5-9ECF-43D4B6087BA2}.Release|x86.Build.0 = Release|x86 + {2E781478-814D-4A48-9D80-BFF206441A65}.Debug|x86.ActiveCfg = Debug|Any CPU + {2E781478-814D-4A48-9D80-BFF206441A65}.Debug|x86.Build.0 = Debug|Any CPU + {2E781478-814D-4A48-9D80-BFF206441A65}.Release|x86.ActiveCfg = Release|Any CPU + {2E781478-814D-4A48-9D80-BFF206441A65}.Release|x86.Build.0 = Release|Any CPU + {442B5058-DCAF-4263-BB6A-F21E31120A1B}.Debug|x86.ActiveCfg = Debug|Any CPU + {442B5058-DCAF-4263-BB6A-F21E31120A1B}.Debug|x86.Build.0 = Debug|Any CPU + {442B5058-DCAF-4263-BB6A-F21E31120A1B}.Release|x86.ActiveCfg = Release|Any CPU + {442B5058-DCAF-4263-BB6A-F21E31120A1B}.Release|x86.Build.0 = Release|Any CPU + {4FD51AC5-2C16-4308-A993-C3A84F3B4582}.Debug|x86.ActiveCfg = Debug|Any CPU + {4FD51AC5-2C16-4308-A993-C3A84F3B4582}.Debug|x86.Build.0 = Debug|Any CPU + {4FD51AC5-2C16-4308-A993-C3A84F3B4582}.Release|x86.ActiveCfg = Release|Any CPU + {4FD51AC5-2C16-4308-A993-C3A84F3B4582}.Release|x86.Build.0 = Release|Any CPU + {5624B7B5-B5A7-41D8-9F10-CC5611109619}.Debug|x86.ActiveCfg = Debug|Any CPU + {5624B7B5-B5A7-41D8-9F10-CC5611109619}.Debug|x86.Build.0 = Debug|Any CPU + {5624B7B5-B5A7-41D8-9F10-CC5611109619}.Release|x86.ActiveCfg = Release|Any CPU + {5624B7B5-B5A7-41D8-9F10-CC5611109619}.Release|x86.Build.0 = Release|Any CPU + {7EEEB4BB-F3E8-48FC-B4C5-70F0FFF8329B}.Debug|x86.ActiveCfg = Debug|Any CPU + {7EEEB4BB-F3E8-48FC-B4C5-70F0FFF8329B}.Debug|x86.Build.0 = Debug|Any CPU + {7EEEB4BB-F3E8-48FC-B4C5-70F0FFF8329B}.Release|x86.ActiveCfg = Release|Any CPU + {7EEEB4BB-F3E8-48FC-B4C5-70F0FFF8329B}.Release|x86.Build.0 = Release|Any CPU + {9142EEFA-7570-41E1-BFCC-468BB571AF2F}.Debug|x86.ActiveCfg = Debug|Any CPU + {9142EEFA-7570-41E1-BFCC-468BB571AF2F}.Debug|x86.Build.0 = Debug|Any CPU + {9142EEFA-7570-41E1-BFCC-468BB571AF2F}.Release|x86.ActiveCfg = Release|Any CPU + {9142EEFA-7570-41E1-BFCC-468BB571AF2F}.Release|x86.Build.0 = Release|Any CPU + {A7FE75CD-3CB4-4E71-A5BF-5347721EC8E0}.Debug|x86.ActiveCfg = Debug|x86 + {A7FE75CD-3CB4-4E71-A5BF-5347721EC8E0}.Debug|x86.Build.0 = Debug|x86 + {A7FE75CD-3CB4-4E71-A5BF-5347721EC8E0}.Release|x86.ActiveCfg = Release|x86 + {A7FE75CD-3CB4-4E71-A5BF-5347721EC8E0}.Release|x86.Build.0 = Release|x86 + {C4D2573A-3FD3-441F-81AF-174AC4CD4E1D}.Debug|x86.ActiveCfg = Debug|Any CPU + {C4D2573A-3FD3-441F-81AF-174AC4CD4E1D}.Debug|x86.Build.0 = Debug|Any CPU + {C4D2573A-3FD3-441F-81AF-174AC4CD4E1D}.Release|x86.ActiveCfg = Release|Any CPU + {C4D2573A-3FD3-441F-81AF-174AC4CD4E1D}.Release|x86.Build.0 = Release|Any CPU + EndGlobalSection + GlobalSection(MonoDevelopProperties) = preSolution + StartupItem = MediaBrowser.Server.Mono\MediaBrowser.Server.Mono.csproj + EndGlobalSection +EndGlobal diff --git a/MediaBrowser.Mono.userprefs b/MediaBrowser.Mono.userprefs new file mode 100644 index 000000000..95fb57a89 --- /dev/null +++ b/MediaBrowser.Mono.userprefs @@ -0,0 +1,8 @@ + + + + + + + + \ No newline at end of file diff --git a/MediaBrowser.Providers/MediaBrowser.Providers.csproj b/MediaBrowser.Providers/MediaBrowser.Providers.csproj index 139c622fc..ef94d77d1 100644 --- a/MediaBrowser.Providers/MediaBrowser.Providers.csproj +++ b/MediaBrowser.Providers/MediaBrowser.Providers.csproj @@ -13,6 +13,8 @@ 512 ..\ true + 10.0.0 + 2.0 true @@ -32,10 +34,6 @@ 4 - - False - ..\packages\morelinq.1.0.16006\lib\net35\MoreLinq.dll - @@ -44,6 +42,9 @@ + + ..\packages\morelinq.1.0.16006\lib\net35\MoreLinq.dll + @@ -116,15 +117,15 @@ - {9142eefa-7570-41e1-bfcc-468bb571af2f} + {9142EEFA-7570-41E1-BFCC-468BB571AF2F} MediaBrowser.Common - {17e1f4e6-8abd-4fe5-9ecf-43d4b6087ba2} + {17E1F4E6-8ABD-4FE5-9ECF-43D4B6087BA2} MediaBrowser.Controller - {7eeeb4bb-f3e8-48fc-b4c5-70f0fff8329b} + {7EEEB4BB-F3E8-48FC-B4C5-70F0FFF8329B} MediaBrowser.Model diff --git a/MediaBrowser.Server.Implementations/Library/Validators/GameGenresValidator.cs b/MediaBrowser.Server.Implementations/Library/Validators/GameGenresValidator.cs index eb89210ff..b9e033d23 100644 --- a/MediaBrowser.Server.Implementations/Library/Validators/GameGenresValidator.cs +++ b/MediaBrowser.Server.Implementations/Library/Validators/GameGenresValidator.cs @@ -41,8 +41,6 @@ namespace MediaBrowser.Server.Implementations.Library.Validators /// Task. public async Task Run(IProgress progress, CancellationToken cancellationToken) { - var allItems = _libraryManager.RootFolder.RecursiveChildren.OfType().ToList(); - var userLibraries = _userManager.Users .Select(i => new Tuple>(i.Id, i.RootFolder.GetRecursiveChildren(i).OfType().ToList())) .ToList(); @@ -79,6 +77,10 @@ namespace MediaBrowser.Server.Implementations.Library.Validators { await UpdateItemByNameCounts(name, cancellationToken, masterDictionary[name]).ConfigureAwait(false); } + catch (OperationCanceledException) + { + // Don't clutter the log + } catch (Exception ex) { _logger.ErrorException("Error updating counts for {0}", ex, name); diff --git a/MediaBrowser.Server.Implementations/Library/Validators/GenresValidator.cs b/MediaBrowser.Server.Implementations/Library/Validators/GenresValidator.cs index 9a34dd1b0..e4d989c33 100644 --- a/MediaBrowser.Server.Implementations/Library/Validators/GenresValidator.cs +++ b/MediaBrowser.Server.Implementations/Library/Validators/GenresValidator.cs @@ -42,16 +42,10 @@ namespace MediaBrowser.Server.Implementations.Library.Validators /// Task. public async Task Run(IProgress progress, CancellationToken cancellationToken) { - var allItems = _libraryManager.RootFolder.RecursiveChildren - .Where(i => !(i is IHasMusicGenres) && !(i is Game)) - .ToList(); - var userLibraries = _userManager.Users .Select(i => new Tuple>(i.Id, i.RootFolder.GetRecursiveChildren(i).Where(m => !(m is IHasMusicGenres) && !(m is Game)).ToList())) .ToList(); - var allLibraryItems = allItems; - var masterDictionary = new Dictionary>>(StringComparer.OrdinalIgnoreCase); // Populate counts of items @@ -84,6 +78,10 @@ namespace MediaBrowser.Server.Implementations.Library.Validators { await UpdateItemByNameCounts(name, cancellationToken, masterDictionary[name]).ConfigureAwait(false); } + catch (OperationCanceledException) + { + // Don't clutter the log + } catch (Exception ex) { _logger.ErrorException("Error updating counts for {0}", ex, name); diff --git a/MediaBrowser.Server.Implementations/Library/Validators/MusicGenresValidator.cs b/MediaBrowser.Server.Implementations/Library/Validators/MusicGenresValidator.cs index 1b211d5f4..1edc24762 100644 --- a/MediaBrowser.Server.Implementations/Library/Validators/MusicGenresValidator.cs +++ b/MediaBrowser.Server.Implementations/Library/Validators/MusicGenresValidator.cs @@ -42,16 +42,10 @@ namespace MediaBrowser.Server.Implementations.Library.Validators /// Task. public async Task Run(IProgress progress, CancellationToken cancellationToken) { - var allItems = _libraryManager.RootFolder.RecursiveChildren - .Where(i => i is IHasMusicGenres) - .ToList(); - var userLibraries = _userManager.Users .Select(i => new Tuple>(i.Id, i.RootFolder.GetRecursiveChildren(i).Where(m => m is IHasMusicGenres).ToList())) .ToList(); - var allLibraryItems = allItems; - var masterDictionary = new Dictionary>>(StringComparer.OrdinalIgnoreCase); // Populate counts of items @@ -84,6 +78,10 @@ namespace MediaBrowser.Server.Implementations.Library.Validators { await UpdateItemByNameCounts(name, cancellationToken, masterDictionary[name]).ConfigureAwait(false); } + catch (OperationCanceledException) + { + // Don't clutter the log + } catch (Exception ex) { _logger.ErrorException("Error updating counts for {0}", ex, name); diff --git a/MediaBrowser.Server.Implementations/Library/Validators/StudiosValidator.cs b/MediaBrowser.Server.Implementations/Library/Validators/StudiosValidator.cs index a4d880329..05689f8e5 100644 --- a/MediaBrowser.Server.Implementations/Library/Validators/StudiosValidator.cs +++ b/MediaBrowser.Server.Implementations/Library/Validators/StudiosValidator.cs @@ -41,14 +41,10 @@ namespace MediaBrowser.Server.Implementations.Library.Validators /// Task. public async Task Run(IProgress progress, CancellationToken cancellationToken) { - var allItems = _libraryManager.RootFolder.RecursiveChildren.ToList(); - var userLibraries = _userManager.Users .Select(i => new Tuple>(i.Id, i.RootFolder.GetRecursiveChildren(i).ToList())) .ToList(); - var allLibraryItems = allItems; - var masterDictionary = new Dictionary>>(StringComparer.OrdinalIgnoreCase); // Populate counts of items @@ -81,6 +77,10 @@ namespace MediaBrowser.Server.Implementations.Library.Validators { await UpdateItemByNameCounts(name, cancellationToken, masterDictionary[name]).ConfigureAwait(false); } + catch (OperationCanceledException) + { + // Don't clutter the log + } catch (Exception ex) { _logger.ErrorException("Error updating counts for {0}", ex, name); diff --git a/MediaBrowser.Server.Implementations/MediaBrowser.Server.Implementations.csproj b/MediaBrowser.Server.Implementations/MediaBrowser.Server.Implementations.csproj index 3c2021750..e44089cc1 100644 --- a/MediaBrowser.Server.Implementations/MediaBrowser.Server.Implementations.csproj +++ b/MediaBrowser.Server.Implementations/MediaBrowser.Server.Implementations.csproj @@ -13,6 +13,8 @@ 512 ..\ true + 10.0.0 + 2.0 true @@ -35,77 +37,65 @@ ..\packages\Alchemy.2.2.1\lib\net40\Alchemy.dll - - False - ..\packages\MediaBrowser.BdInfo.1.0.0.2\lib\net45\BdInfo.dll - ..\packages\SharpZipLib.0.86.0\lib\20\ICSharpCode.SharpZipLib.dll ..\packages\Lucene.Net.3.0.3\lib\NET40\Lucene.Net.dll - - False + + + + + ..\packages\Rx-Core.2.1.30214.0\lib\Net45\System.Reactive.Core.dll + + + ..\packages\Rx-Interfaces.2.1.30214.0\lib\Net45\System.Reactive.Interfaces.dll + + + ..\packages\Rx-Linq.2.1.30214.0\lib\Net45\System.Reactive.Linq.dll + + + + + + + + ..\packages\MediaBrowser.BdInfo.1.0.0.2\lib\net45\BdInfo.dll + + ..\packages\morelinq.1.0.16006\lib\net35\MoreLinq.dll - - False + ..\packages\ServiceStack.3.9.62\lib\net35\ServiceStack.dll - - False + ..\packages\ServiceStack.Api.Swagger.3.9.59\lib\net35\ServiceStack.Api.Swagger.dll - - False + ..\packages\ServiceStack.Common.3.9.62\lib\net35\ServiceStack.Common.dll - - False + ..\packages\ServiceStack.Common.3.9.62\lib\net35\ServiceStack.Interfaces.dll - - False + ..\packages\ServiceStack.OrmLite.SqlServer.3.9.43\lib\ServiceStack.OrmLite.SqlServer.dll - - False + ..\packages\ServiceStack.Redis.3.9.43\lib\net35\ServiceStack.Redis.dll - - False + ..\packages\ServiceStack.3.9.62\lib\net35\ServiceStack.ServiceInterface.dll - - False + ..\packages\ServiceStack.Text.3.9.62\lib\net35\ServiceStack.Text.dll - - - - False + ..\packages\System.Data.SQLite.x86.1.0.88.0\lib\net45\System.Data.SQLite.dll - - False + ..\packages\System.Data.SQLite.x86.1.0.88.0\lib\net45\System.Data.SQLite.Linq.dll - - - ..\packages\Rx-Core.2.1.30214.0\lib\Net45\System.Reactive.Core.dll - - - ..\packages\Rx-Interfaces.2.1.30214.0\lib\Net45\System.Reactive.Interfaces.dll - - - ..\packages\Rx-Linq.2.1.30214.0\lib\Net45\System.Reactive.Linq.dll - - - - - - @@ -223,19 +213,19 @@ - {c4d2573a-3fd3-441f-81af-174ac4cd4e1d} + {C4D2573A-3FD3-441F-81AF-174AC4CD4E1D} MediaBrowser.Common.Implementations - {9142eefa-7570-41e1-bfcc-468bb571af2f} + {9142EEFA-7570-41E1-BFCC-468BB571AF2F} MediaBrowser.Common - {17e1f4e6-8abd-4fe5-9ecf-43d4b6087ba2} + {17E1F4E6-8ABD-4FE5-9ECF-43D4B6087BA2} MediaBrowser.Controller - {7eeeb4bb-f3e8-48fc-b4c5-70f0fff8329b} + {7EEEB4BB-F3E8-48FC-B4C5-70F0FFF8329B} MediaBrowser.Model diff --git a/MediaBrowser.Server.Mono/MainWindow.cs b/MediaBrowser.Server.Mono/MainWindow.cs new file mode 100644 index 000000000..229f44dab --- /dev/null +++ b/MediaBrowser.Server.Mono/MainWindow.cs @@ -0,0 +1,16 @@ +using System; +using Gtk; + +public partial class MainWindow: Gtk.Window +{ + public MainWindow (): base (Gtk.WindowType.Toplevel) + { + Build (); + } + + protected void OnDeleteEvent (object sender, DeleteEventArgs a) + { + Application.Quit (); + a.RetVal = true; + } +} diff --git a/MediaBrowser.Server.Mono/MediaBrowser.Server.Mono.csproj b/MediaBrowser.Server.Mono/MediaBrowser.Server.Mono.csproj new file mode 100644 index 000000000..a97ab4fac --- /dev/null +++ b/MediaBrowser.Server.Mono/MediaBrowser.Server.Mono.csproj @@ -0,0 +1,91 @@ + + + + Debug + x86 + 10.0.0 + 2.0 + {A7FE75CD-3CB4-4E71-A5BF-5347721EC8E0} + WinExe + MediaBrowser.Server.Mono + MediaBrowser.Server.Mono + v4.5 + + + true + full + false + bin\Debug + DEBUG; + prompt + 4 + x86 + false + + + full + true + bin\Release + prompt + 4 + x86 + false + + + + + + + + + + + + + + gui.stetic + + + + + + + + + + + + + {5624B7B5-B5A7-41D8-9F10-CC5611109619} + MediaBrowser.WebDashboard + + + {2E781478-814D-4A48-9D80-BFF206441A65} + MediaBrowser.Server.Implementations + + + {442B5058-DCAF-4263-BB6A-F21E31120A1B} + MediaBrowser.Providers + + + {7EEEB4BB-F3E8-48FC-B4C5-70F0FFF8329B} + MediaBrowser.Model + + + {17E1F4E6-8ABD-4FE5-9ECF-43D4B6087BA2} + MediaBrowser.Controller + + + {C4D2573A-3FD3-441F-81AF-174AC4CD4E1D} + MediaBrowser.Common.Implementations + + + {9142EEFA-7570-41E1-BFCC-468BB571AF2F} + MediaBrowser.Common + + + {4FD51AC5-2C16-4308-A993-C3A84F3B4582} + MediaBrowser.Api + + + \ No newline at end of file diff --git a/MediaBrowser.Server.Mono/Program.cs b/MediaBrowser.Server.Mono/Program.cs new file mode 100644 index 000000000..72dee1162 --- /dev/null +++ b/MediaBrowser.Server.Mono/Program.cs @@ -0,0 +1,16 @@ +using System; +using Gtk; + +namespace MediaBrowser.Server.Mono +{ + class MainClass + { + public static void Main (string[] args) + { + Application.Init (); + MainWindow win = new MainWindow (); + win.Show (); + Application.Run (); + } + } +} diff --git a/MediaBrowser.Server.Mono/Properties/AssemblyInfo.cs b/MediaBrowser.Server.Mono/Properties/AssemblyInfo.cs new file mode 100644 index 000000000..0a2e93220 --- /dev/null +++ b/MediaBrowser.Server.Mono/Properties/AssemblyInfo.cs @@ -0,0 +1,22 @@ +using System.Reflection; +using System.Runtime.CompilerServices; + +// Information about this assembly is defined by the following attributes. +// Change them to the values specific to your project. +[assembly: AssemblyTitle ("MediaBrowser.Server.Mono")] +[assembly: AssemblyDescription ("")] +[assembly: AssemblyConfiguration ("")] +[assembly: AssemblyCompany ("")] +[assembly: AssemblyProduct ("")] +[assembly: AssemblyCopyright ("Luke")] +[assembly: AssemblyTrademark ("")] +[assembly: AssemblyCulture ("")] +// The assembly version has the format "{Major}.{Minor}.{Build}.{Revision}". +// The form "{Major}.{Minor}.*" will automatically update the build and revision, +// and "{Major}.{Minor}.{Build}.*" will update just the revision. +[assembly: AssemblyVersion ("1.0.*")] +// The following attributes are used to specify the signing key for the assembly, +// if desired. See the Mono documentation for more information about signing. +//[assembly: AssemblyDelaySign(false)] +//[assembly: AssemblyKeyFile("")] + diff --git a/MediaBrowser.Server.Mono/gtk-gui/MainWindow.cs b/MediaBrowser.Server.Mono/gtk-gui/MainWindow.cs new file mode 100644 index 000000000..c481dfc8c --- /dev/null +++ b/MediaBrowser.Server.Mono/gtk-gui/MainWindow.cs @@ -0,0 +1,20 @@ + +// This file has been generated by the GUI designer. Do not modify. +public partial class MainWindow +{ + protected virtual void Build () + { + global::Stetic.Gui.Initialize (this); + // Widget MainWindow + this.Name = "MainWindow"; + this.Title = global::Mono.Unix.Catalog.GetString ("MainWindow"); + this.WindowPosition = ((global::Gtk.WindowPosition)(4)); + if ((this.Child != null)) { + this.Child.ShowAll (); + } + this.DefaultWidth = 400; + this.DefaultHeight = 300; + this.Show (); + this.DeleteEvent += new global::Gtk.DeleteEventHandler (this.OnDeleteEvent); + } +} diff --git a/MediaBrowser.Server.Mono/gtk-gui/generated.cs b/MediaBrowser.Server.Mono/gtk-gui/generated.cs new file mode 100644 index 000000000..9ef336398 --- /dev/null +++ b/MediaBrowser.Server.Mono/gtk-gui/generated.cs @@ -0,0 +1,29 @@ + +// This file has been generated by the GUI designer. Do not modify. +namespace Stetic +{ + internal class Gui + { + private static bool initialized; + + internal static void Initialize (Gtk.Widget iconRenderer) + { + if ((Stetic.Gui.initialized == false)) { + Stetic.Gui.initialized = true; + } + } + } + + internal class ActionGroups + { + public static Gtk.ActionGroup GetActionGroup (System.Type type) + { + return Stetic.ActionGroups.GetActionGroup (type.FullName); + } + + public static Gtk.ActionGroup GetActionGroup (string name) + { + return null; + } + } +} diff --git a/MediaBrowser.Server.Mono/gtk-gui/gui.stetic b/MediaBrowser.Server.Mono/gtk-gui/gui.stetic new file mode 100644 index 000000000..d564b4446 --- /dev/null +++ b/MediaBrowser.Server.Mono/gtk-gui/gui.stetic @@ -0,0 +1,19 @@ + + + + 2.12 + + + + + + + + MainWindow + CenterOnParent + + + + + + \ No newline at end of file diff --git a/MediaBrowser.WebDashboard/MediaBrowser.WebDashboard.csproj b/MediaBrowser.WebDashboard/MediaBrowser.WebDashboard.csproj index 1fbc01952..6a599da45 100644 --- a/MediaBrowser.WebDashboard/MediaBrowser.WebDashboard.csproj +++ b/MediaBrowser.WebDashboard/MediaBrowser.WebDashboard.csproj @@ -13,6 +13,8 @@ 512 ..\ true + 10.0.0 + 2.0 true @@ -35,24 +37,21 @@ Always - - False - ..\packages\ServiceStack.Common.3.9.62\lib\net35\ServiceStack.Common.dll - - - False - ..\packages\ServiceStack.Common.3.9.62\lib\net35\ServiceStack.Interfaces.dll - - - False - ..\packages\ServiceStack.Text.3.9.62\lib\net35\ServiceStack.Text.dll - + + ..\packages\ServiceStack.Common.3.9.62\lib\net35\ServiceStack.Common.dll + + + ..\packages\ServiceStack.Common.3.9.62\lib\net35\ServiceStack.Interfaces.dll + + + ..\packages\ServiceStack.Text.3.9.62\lib\net35\ServiceStack.Text.dll + @@ -67,15 +66,15 @@ - {9142eefa-7570-41e1-bfcc-468bb571af2f} + {9142EEFA-7570-41E1-BFCC-468BB571AF2F} MediaBrowser.Common - {17e1f4e6-8abd-4fe5-9ecf-43d4b6087ba2} + {17E1F4E6-8ABD-4FE5-9ECF-43D4B6087BA2} MediaBrowser.Controller - {7eeeb4bb-f3e8-48fc-b4c5-70f0fff8329b} + {7EEEB4BB-F3E8-48FC-B4C5-70F0FFF8329B} MediaBrowser.Model -- cgit v1.2.3 From 2d9b48d00fd31aaa96676c82a054b2794493fbf9 Mon Sep 17 00:00:00 2001 From: Luke Pulverenti Date: Wed, 25 Sep 2013 11:11:23 -0400 Subject: fixed ffprobe running over and over --- MediaBrowser.Api/ApiEntryPoint.cs | 2 +- .../Providers/BaseMetadataProvider.cs | 2 +- MediaBrowser.Controller/Session/SessionInfo.cs | 6 +-- .../MediaInfo/FFProbeVideoInfoProvider.cs | 1 + MediaBrowser.Providers/Savers/AlbumXmlSaver.cs | 5 +- MediaBrowser.Providers/Savers/ArtistXmlSaver.cs | 5 +- MediaBrowser.Providers/Savers/BoxSetXmlSaver.cs | 5 +- MediaBrowser.Providers/Savers/EpisodeXmlSaver.cs | 5 +- MediaBrowser.Providers/Savers/FolderXmlSaver.cs | 3 +- MediaBrowser.Providers/Savers/GameXmlSaver.cs | 7 +-- MediaBrowser.Providers/Savers/MovieXmlSaver.cs | 5 +- MediaBrowser.Providers/Savers/PersonXmlSaver.cs | 5 +- MediaBrowser.Providers/Savers/SeasonXmlSaver.cs | 3 +- MediaBrowser.Providers/Savers/SeriesXmlSaver.cs | 5 +- MediaBrowser.Providers/Savers/XmlSaverHelpers.cs | 53 ++++++++++++++++------ .../MediaEncoder/MediaEncoder.cs | 2 +- .../ScheduledTasks/ChapterImagesTask.cs | 4 ++ 17 files changed, 80 insertions(+), 38 deletions(-) (limited to 'MediaBrowser.Controller') diff --git a/MediaBrowser.Api/ApiEntryPoint.cs b/MediaBrowser.Api/ApiEntryPoint.cs index 273d9a7a9..8754e57a1 100644 --- a/MediaBrowser.Api/ApiEntryPoint.cs +++ b/MediaBrowser.Api/ApiEntryPoint.cs @@ -180,7 +180,7 @@ namespace MediaBrowser.Api if (job.ActiveRequestCount == 0) { - var timerDuration = type == TranscodingJobType.Progressive ? 1000 : 60000; + var timerDuration = type == TranscodingJobType.Progressive ? 1000 : 180000; if (job.KillTimer == null) { diff --git a/MediaBrowser.Controller/Providers/BaseMetadataProvider.cs b/MediaBrowser.Controller/Providers/BaseMetadataProvider.cs index a8dc8788f..2364debed 100644 --- a/MediaBrowser.Controller/Providers/BaseMetadataProvider.cs +++ b/MediaBrowser.Controller/Providers/BaseMetadataProvider.cs @@ -385,7 +385,7 @@ namespace MediaBrowser.Controller.Providers var sb = new StringBuilder(); var extensions = FileStampExtensionsDictionary; - var numExtensions = extensions.Count; + var numExtensions = FilestampExtensions.Length; // Record the name of each file // Need to sort these because accoring to msdn docs, our i/o methods are not guaranteed in any order diff --git a/MediaBrowser.Controller/Session/SessionInfo.cs b/MediaBrowser.Controller/Session/SessionInfo.cs index ba6d3d0ac..dc934b70a 100644 --- a/MediaBrowser.Controller/Session/SessionInfo.cs +++ b/MediaBrowser.Controller/Session/SessionInfo.cs @@ -83,7 +83,7 @@ namespace MediaBrowser.Controller.Session /// /// The name of the now viewing item. public string NowViewingItemName { get; set; } - + /// /// Gets or sets the now playing item. /// @@ -107,7 +107,7 @@ namespace MediaBrowser.Controller.Session /// /// true if this instance is muted; otherwise, false. public bool IsMuted { get; set; } - + /// /// Gets or sets the device id. /// @@ -139,7 +139,7 @@ namespace MediaBrowser.Controller.Session return WebSockets.Any(i => i.State == WebSocketState.Open); } - return (DateTime.UtcNow - LastActivityDate).TotalMinutes <= 5; + return (DateTime.UtcNow - LastActivityDate).TotalMinutes <= 10; } } diff --git a/MediaBrowser.Providers/MediaInfo/FFProbeVideoInfoProvider.cs b/MediaBrowser.Providers/MediaInfo/FFProbeVideoInfoProvider.cs index 690c9b3ff..c28d06cbb 100644 --- a/MediaBrowser.Providers/MediaInfo/FFProbeVideoInfoProvider.cs +++ b/MediaBrowser.Providers/MediaInfo/FFProbeVideoInfoProvider.cs @@ -178,6 +178,7 @@ namespace MediaBrowser.Providers.MediaInfo } } + SetLastRefreshed(item, DateTime.UtcNow); return true; } diff --git a/MediaBrowser.Providers/Savers/AlbumXmlSaver.cs b/MediaBrowser.Providers/Savers/AlbumXmlSaver.cs index e6195c03e..bd63b5fbd 100644 --- a/MediaBrowser.Providers/Savers/AlbumXmlSaver.cs +++ b/MediaBrowser.Providers/Savers/AlbumXmlSaver.cs @@ -1,4 +1,5 @@ -using MediaBrowser.Controller.Configuration; +using System.Collections.Generic; +using MediaBrowser.Controller.Configuration; using MediaBrowser.Controller.Entities; using MediaBrowser.Controller.Entities.Audio; using MediaBrowser.Controller.Library; @@ -58,7 +59,7 @@ namespace MediaBrowser.Providers.Savers var xmlFilePath = GetSavePath(item); - XmlSaverHelpers.Save(builder, xmlFilePath, new string[] { }); + XmlSaverHelpers.Save(builder, xmlFilePath, new List { }); // Set last refreshed so that the provider doesn't trigger after the file save PersonProviderFromXml.Current.SetLastRefreshed(item, DateTime.UtcNow); diff --git a/MediaBrowser.Providers/Savers/ArtistXmlSaver.cs b/MediaBrowser.Providers/Savers/ArtistXmlSaver.cs index 795e824fc..a27fb7363 100644 --- a/MediaBrowser.Providers/Savers/ArtistXmlSaver.cs +++ b/MediaBrowser.Providers/Savers/ArtistXmlSaver.cs @@ -1,4 +1,5 @@ -using MediaBrowser.Controller.Configuration; +using System.Collections.Generic; +using MediaBrowser.Controller.Configuration; using MediaBrowser.Controller.Entities; using MediaBrowser.Controller.Entities.Audio; using MediaBrowser.Controller.Library; @@ -70,7 +71,7 @@ namespace MediaBrowser.Providers.Savers var xmlFilePath = GetSavePath(item); - XmlSaverHelpers.Save(builder, xmlFilePath, new string[] { }); + XmlSaverHelpers.Save(builder, xmlFilePath, new List { }); // Set last refreshed so that the provider doesn't trigger after the file save ArtistProviderFromXml.Current.SetLastRefreshed(item, DateTime.UtcNow); diff --git a/MediaBrowser.Providers/Savers/BoxSetXmlSaver.cs b/MediaBrowser.Providers/Savers/BoxSetXmlSaver.cs index f5fc37fe7..f09b34570 100644 --- a/MediaBrowser.Providers/Savers/BoxSetXmlSaver.cs +++ b/MediaBrowser.Providers/Savers/BoxSetXmlSaver.cs @@ -1,4 +1,5 @@ -using MediaBrowser.Controller.Configuration; +using System.Collections.Generic; +using MediaBrowser.Controller.Configuration; using MediaBrowser.Controller.Entities; using MediaBrowser.Controller.Entities.Movies; using MediaBrowser.Controller.Library; @@ -57,7 +58,7 @@ namespace MediaBrowser.Providers.Savers var xmlFilePath = GetSavePath(item); - XmlSaverHelpers.Save(builder, xmlFilePath, new string[] { }); + XmlSaverHelpers.Save(builder, xmlFilePath, new List { }); BoxSetProviderFromXml.Current.SetLastRefreshed(item, DateTime.UtcNow); } diff --git a/MediaBrowser.Providers/Savers/EpisodeXmlSaver.cs b/MediaBrowser.Providers/Savers/EpisodeXmlSaver.cs index d90cb94c2..854c508b9 100644 --- a/MediaBrowser.Providers/Savers/EpisodeXmlSaver.cs +++ b/MediaBrowser.Providers/Savers/EpisodeXmlSaver.cs @@ -1,4 +1,5 @@ -using MediaBrowser.Controller.Configuration; +using System.Collections.Generic; +using MediaBrowser.Controller.Configuration; using MediaBrowser.Controller.Entities; using MediaBrowser.Controller.Entities.TV; using MediaBrowser.Controller.Library; @@ -87,7 +88,7 @@ namespace MediaBrowser.Providers.Savers var xmlFilePath = GetSavePath(item); - XmlSaverHelpers.Save(builder, xmlFilePath, new[] + XmlSaverHelpers.Save(builder, xmlFilePath, new List { "FirstAired", "SeasonNumber", diff --git a/MediaBrowser.Providers/Savers/FolderXmlSaver.cs b/MediaBrowser.Providers/Savers/FolderXmlSaver.cs index 23339ec75..6e95cc8c5 100644 --- a/MediaBrowser.Providers/Savers/FolderXmlSaver.cs +++ b/MediaBrowser.Providers/Savers/FolderXmlSaver.cs @@ -1,4 +1,5 @@ using System; +using System.Collections.Generic; using MediaBrowser.Controller.Configuration; using MediaBrowser.Controller.Entities; using MediaBrowser.Controller.Entities.Audio; @@ -77,7 +78,7 @@ namespace MediaBrowser.Providers.Savers var xmlFilePath = GetSavePath(item); - XmlSaverHelpers.Save(builder, xmlFilePath, new string[] { }); + XmlSaverHelpers.Save(builder, xmlFilePath, new List { }); FolderProviderFromXml.Current.SetLastRefreshed(item, DateTime.UtcNow); } diff --git a/MediaBrowser.Providers/Savers/GameXmlSaver.cs b/MediaBrowser.Providers/Savers/GameXmlSaver.cs index 41bd364c8..1e654f72f 100644 --- a/MediaBrowser.Providers/Savers/GameXmlSaver.cs +++ b/MediaBrowser.Providers/Savers/GameXmlSaver.cs @@ -1,4 +1,5 @@ -using MediaBrowser.Controller.Configuration; +using System.Collections.Generic; +using MediaBrowser.Controller.Configuration; using MediaBrowser.Controller.Entities; using MediaBrowser.Controller.Library; using MediaBrowser.Providers.Movies; @@ -66,7 +67,7 @@ namespace MediaBrowser.Providers.Savers if (!string.IsNullOrEmpty(game.GameSystem)) { - builder.Append(""); + builder.Append("" + SecurityElement.Escape(game.GameSystem) + ""); } XmlSaverHelpers.AddCommonNodes(item, builder); @@ -75,7 +76,7 @@ namespace MediaBrowser.Providers.Savers var xmlFilePath = GetSavePath(item); - XmlSaverHelpers.Save(builder, xmlFilePath, new[] + XmlSaverHelpers.Save(builder, xmlFilePath, new List { "Players", "GameSystem" diff --git a/MediaBrowser.Providers/Savers/MovieXmlSaver.cs b/MediaBrowser.Providers/Savers/MovieXmlSaver.cs index 2402bcd7f..761bcefd1 100644 --- a/MediaBrowser.Providers/Savers/MovieXmlSaver.cs +++ b/MediaBrowser.Providers/Savers/MovieXmlSaver.cs @@ -1,4 +1,5 @@ -using MediaBrowser.Controller.Configuration; +using System.Collections.Generic; +using MediaBrowser.Controller.Configuration; using MediaBrowser.Controller.Entities; using MediaBrowser.Controller.Entities.Movies; using MediaBrowser.Controller.Library; @@ -103,7 +104,7 @@ namespace MediaBrowser.Providers.Savers var xmlFilePath = GetSavePath(item); - XmlSaverHelpers.Save(builder, xmlFilePath, new[] + XmlSaverHelpers.Save(builder, xmlFilePath, new List { "IMDBrating", "Description", diff --git a/MediaBrowser.Providers/Savers/PersonXmlSaver.cs b/MediaBrowser.Providers/Savers/PersonXmlSaver.cs index 1b1377ac8..92f6db29b 100644 --- a/MediaBrowser.Providers/Savers/PersonXmlSaver.cs +++ b/MediaBrowser.Providers/Savers/PersonXmlSaver.cs @@ -1,4 +1,5 @@ -using System.Security; +using System.Collections.Generic; +using System.Security; using MediaBrowser.Controller.Entities; using MediaBrowser.Controller.Library; using MediaBrowser.Providers.Movies; @@ -57,7 +58,7 @@ namespace MediaBrowser.Providers.Savers var xmlFilePath = GetSavePath(item); - XmlSaverHelpers.Save(builder, xmlFilePath, new[] + XmlSaverHelpers.Save(builder, xmlFilePath, new List { "PlaceOfBirth" }); diff --git a/MediaBrowser.Providers/Savers/SeasonXmlSaver.cs b/MediaBrowser.Providers/Savers/SeasonXmlSaver.cs index 97e8b671f..e484b3d39 100644 --- a/MediaBrowser.Providers/Savers/SeasonXmlSaver.cs +++ b/MediaBrowser.Providers/Savers/SeasonXmlSaver.cs @@ -1,4 +1,5 @@ using System; +using System.Collections.Generic; using MediaBrowser.Controller.Configuration; using MediaBrowser.Controller.Entities; using MediaBrowser.Controller.Entities.TV; @@ -57,7 +58,7 @@ namespace MediaBrowser.Providers.Savers var xmlFilePath = GetSavePath(item); - XmlSaverHelpers.Save(builder, xmlFilePath, new string[] { }); + XmlSaverHelpers.Save(builder, xmlFilePath, new List { }); SeasonProviderFromXml.Current.SetLastRefreshed(item, DateTime.UtcNow); } diff --git a/MediaBrowser.Providers/Savers/SeriesXmlSaver.cs b/MediaBrowser.Providers/Savers/SeriesXmlSaver.cs index 6b9828576..a4ff9c7d8 100644 --- a/MediaBrowser.Providers/Savers/SeriesXmlSaver.cs +++ b/MediaBrowser.Providers/Savers/SeriesXmlSaver.cs @@ -1,4 +1,5 @@ -using MediaBrowser.Controller.Configuration; +using System.Collections.Generic; +using MediaBrowser.Controller.Configuration; using MediaBrowser.Controller.Entities; using MediaBrowser.Controller.Entities.TV; using MediaBrowser.Controller.Library; @@ -105,7 +106,7 @@ namespace MediaBrowser.Providers.Savers var xmlFilePath = GetSavePath(item); - XmlSaverHelpers.Save(builder, xmlFilePath, new[] + XmlSaverHelpers.Save(builder, xmlFilePath, new List { "id", "SeriesName", diff --git a/MediaBrowser.Providers/Savers/XmlSaverHelpers.cs b/MediaBrowser.Providers/Savers/XmlSaverHelpers.cs index cea7cf926..338447c10 100644 --- a/MediaBrowser.Providers/Savers/XmlSaverHelpers.cs +++ b/MediaBrowser.Providers/Savers/XmlSaverHelpers.cs @@ -29,13 +29,11 @@ namespace MediaBrowser.Providers.Savers /// The XML. /// The path. /// The XML tags used. - public static void Save(StringBuilder xml, string path, IEnumerable xmlTagsUsed) + public static void Save(StringBuilder xml, string path, List xmlTagsUsed) { if (File.Exists(path)) { - var tags = xmlTagsUsed.ToList(); - - tags.AddRange(new[] + xmlTagsUsed.AddRange(new[] { "MediaInfo", "ContentRating", @@ -88,7 +86,7 @@ namespace MediaBrowser.Providers.Savers }); var position = xml.ToString().LastIndexOf("The path. /// The XML tags used. /// System.String. - private static string GetCustomTags(string path, ICollection xmlTagsUsed) + private static string GetCustomTags(string path, IEnumerable xmlTagsUsed) { - var doc = new XmlDocument(); - doc.Load(path); + var settings = new XmlReaderSettings + { + CheckCharacters = false, + IgnoreProcessingInstructions = true, + IgnoreComments = true, + ValidationType = ValidationType.None + }; + + var tagsDictionary = xmlTagsUsed.ToDictionary(i => i, StringComparer.OrdinalIgnoreCase); - var nodes = doc.DocumentElement.ChildNodes.Cast() - .Where(i => !xmlTagsUsed.Contains(i.Name)) - .Select(i => i.OuterXml) - .ToArray(); + var builder = new StringBuilder(); + + using (var streamReader = new StreamReader(path, Encoding.UTF8)) + { + // Use XmlReader for best performance + using (var reader = XmlReader.Create(streamReader, settings)) + { + reader.MoveToContent(); - return string.Join(Environment.NewLine, nodes); + // Loop through each element + while (reader.Read()) + { + if (reader.NodeType == XmlNodeType.Element) + { + if (!tagsDictionary.ContainsKey(reader.Name)) + { + builder.AppendLine(reader.ReadOuterXml()); + } + else + { + reader.Skip(); + } + } + } + } + } + + return builder.ToString(); } /// diff --git a/MediaBrowser.Server.Implementations/MediaEncoder/MediaEncoder.cs b/MediaBrowser.Server.Implementations/MediaEncoder/MediaEncoder.cs index b24c9a5ca..2f353b8c0 100644 --- a/MediaBrowser.Server.Implementations/MediaEncoder/MediaEncoder.cs +++ b/MediaBrowser.Server.Implementations/MediaEncoder/MediaEncoder.cs @@ -57,7 +57,7 @@ namespace MediaBrowser.Server.Implementations.MediaEncoder /// /// The FF probe resource pool /// - private readonly SemaphoreSlim _ffProbeResourcePool = new SemaphoreSlim(2, 2); + private readonly SemaphoreSlim _ffProbeResourcePool = new SemaphoreSlim(1, 1); public string FFMpegPath { get; private set; } diff --git a/MediaBrowser.Server.Implementations/ScheduledTasks/ChapterImagesTask.cs b/MediaBrowser.Server.Implementations/ScheduledTasks/ChapterImagesTask.cs index d9b88368b..4829dc405 100644 --- a/MediaBrowser.Server.Implementations/ScheduledTasks/ChapterImagesTask.cs +++ b/MediaBrowser.Server.Implementations/ScheduledTasks/ChapterImagesTask.cs @@ -159,6 +159,10 @@ namespace MediaBrowser.Server.Implementations.ScheduledTasks { previouslyFailedImages = new List(); } + catch (DirectoryNotFoundException) + { + previouslyFailedImages = new List(); + } foreach (var video in videos) { -- cgit v1.2.3