diff options
| author | Luke Pulverenti <luke.pulverenti@gmail.com> | 2014-10-23 00:26:01 -0400 |
|---|---|---|
| committer | Luke Pulverenti <luke.pulverenti@gmail.com> | 2014-10-23 00:26:01 -0400 |
| commit | 5a5b48feff3a0b0a660aaaa9bdfd04fd0fe711ed (patch) | |
| tree | 47079574a89158a371f91392992e9ebe9b7840ba /MediaBrowser.Server.Implementations | |
| parent | 35f40993b2b85efc6fbb677d373b337aebfe0465 (diff) | |
added new cabac value
Diffstat (limited to 'MediaBrowser.Server.Implementations')
13 files changed, 313 insertions, 71 deletions
diff --git a/MediaBrowser.Server.Implementations/Configuration/ServerConfigurationManager.cs b/MediaBrowser.Server.Implementations/Configuration/ServerConfigurationManager.cs index 1370b2bf2..4abe56aca 100644 --- a/MediaBrowser.Server.Implementations/Configuration/ServerConfigurationManager.cs +++ b/MediaBrowser.Server.Implementations/Configuration/ServerConfigurationManager.cs @@ -3,6 +3,8 @@ using MediaBrowser.Common.Events; using MediaBrowser.Common.Implementations.Configuration; using MediaBrowser.Controller; using MediaBrowser.Controller.Configuration; +using MediaBrowser.Controller.Entities; +using MediaBrowser.Controller.Entities.Audio; using MediaBrowser.Controller.Entities.Movies; using MediaBrowser.Controller.Entities.TV; using MediaBrowser.Model.Configuration; @@ -214,6 +216,11 @@ namespace MediaBrowser.Server.Implementations.Configuration DisableMetadataService(typeof(Movie), Configuration, service); DisableMetadataService(typeof(Episode), Configuration, service); DisableMetadataService(typeof(Series), Configuration, service); + DisableMetadataService(typeof(Season), Configuration, service); + DisableMetadataService(typeof(MusicArtist), Configuration, service); + DisableMetadataService(typeof(MusicAlbum), Configuration, service); + DisableMetadataService(typeof(MusicVideo), Configuration, service); + DisableMetadataService(typeof(Video), Configuration, service); } private void DisableMetadataService(Type type, ServerConfiguration config, string service) diff --git a/MediaBrowser.Server.Implementations/Connect/ConnectManager.cs b/MediaBrowser.Server.Implementations/Connect/ConnectManager.cs index 88f934d25..f468606ed 100644 --- a/MediaBrowser.Server.Implementations/Connect/ConnectManager.cs +++ b/MediaBrowser.Server.Implementations/Connect/ConnectManager.cs @@ -141,6 +141,8 @@ namespace MediaBrowser.Server.Implementations.Connect try { + var localAddress = _appHost.GetSystemInfo().LocalAddress; + var hasExistingRecord = !string.IsNullOrWhiteSpace(ConnectServerId) && !string.IsNullOrWhiteSpace(ConnectAccessKey); @@ -150,11 +152,12 @@ namespace MediaBrowser.Server.Implementations.Connect { try { - await UpdateServerRegistration(wanApiAddress).ConfigureAwait(false); + await UpdateServerRegistration(wanApiAddress, localAddress).ConfigureAwait(false); } catch (HttpException ex) { - if (!ex.StatusCode.HasValue || !new[] { HttpStatusCode.NotFound, HttpStatusCode.Unauthorized }.Contains(ex.StatusCode.Value)) + if (!ex.StatusCode.HasValue || + !new[] { HttpStatusCode.NotFound, HttpStatusCode.Unauthorized }.Contains(ex.StatusCode.Value)) { throw; } @@ -165,7 +168,7 @@ namespace MediaBrowser.Server.Implementations.Connect if (createNewRegistration) { - await CreateServerRegistration(wanApiAddress).ConfigureAwait(false); + await CreateServerRegistration(wanApiAddress, localAddress).ConfigureAwait(false); } await RefreshAuthorizationsInternal(true, CancellationToken.None).ConfigureAwait(false); @@ -176,7 +179,7 @@ namespace MediaBrowser.Server.Implementations.Connect } } - private async Task CreateServerRegistration(string wanApiAddress) + private async Task CreateServerRegistration(string wanApiAddress, string localAddress) { var url = "Servers"; url = GetConnectUrl(url); @@ -188,6 +191,11 @@ namespace MediaBrowser.Server.Implementations.Connect {"systemId", _appHost.SystemId} }; + if (!string.IsNullOrWhiteSpace(localAddress)) + { + postData["localAddress"] = localAddress; + } + using (var stream = await _httpClient.Post(url, postData, CancellationToken.None).ConfigureAwait(false)) { var data = _json.DeserializeFromStream<ServerRegistrationResponse>(stream); @@ -199,24 +207,31 @@ namespace MediaBrowser.Server.Implementations.Connect } } - private async Task UpdateServerRegistration(string wanApiAddress) + private async Task UpdateServerRegistration(string wanApiAddress, string localAddress) { var url = "Servers"; url = GetConnectUrl(url); url += "?id=" + ConnectServerId; + var postData = new Dictionary<string, string> + { + {"name", _appHost.FriendlyName}, + {"url", wanApiAddress}, + {"systemId", _appHost.SystemId} + }; + + if (!string.IsNullOrWhiteSpace(localAddress)) + { + postData["localAddress"] = localAddress; + } + var options = new HttpRequestOptions { Url = url, CancellationToken = CancellationToken.None }; - options.SetPostData(new Dictionary<string, string> - { - {"name", _appHost.FriendlyName}, - {"url", wanApiAddress}, - {"systemId", _appHost.SystemId} - }); + options.SetPostData(postData); SetServerAccessToken(options); @@ -405,15 +420,46 @@ namespace MediaBrowser.Server.Implementations.Connect throw new ArgumentNullException("connectUsername"); } - var connectUser = await GetConnectUser(new ConnectUserQuery + string connectUserId = null; + var result = new UserLinkResult(); + + try { - Name = connectUsername + var connectUser = await GetConnectUser(new ConnectUserQuery + { + Name = connectUsername - }, CancellationToken.None).ConfigureAwait(false); + }, CancellationToken.None).ConfigureAwait(false); - if (!connectUser.IsActive) + if (!connectUser.IsActive) + { + throw new ArgumentException("The Media Browser account has been disabled."); + } + + connectUserId = connectUser.Id; + result.GuestDisplayName = connectUser.Name; + } + catch (HttpException ex) { - throw new ArgumentException("The Media Browser account has been disabled."); + if (!ex.StatusCode.HasValue || + ex.StatusCode.Value != HttpStatusCode.NotFound || + !Validator.EmailIsValid(connectUsername)) + { + throw; + } + } + + var sendingUser = GetUser(sendingUserId); + var requesterUserName = sendingUser.ConnectUserName; + + if (string.IsNullOrWhiteSpace(requesterUserName)) + { + requesterUserName = sendingUser.Name; + } + + if (string.IsNullOrWhiteSpace(connectUserId)) + { + return await SendNewUserInvitation(requesterUserName, connectUsername).ConfigureAwait(false); } var url = GetConnectUrl("ServerAuthorizations"); @@ -425,18 +471,11 @@ namespace MediaBrowser.Server.Implementations.Connect }; var accessToken = Guid.NewGuid().ToString("N"); - var sendingUser = GetUser(sendingUserId); - - var requesterUserName = sendingUser.ConnectUserName; - if (string.IsNullOrWhiteSpace(requesterUserName)) - { - requesterUserName = sendingUser.Name; - } var postData = new Dictionary<string, string> { {"serverId", ConnectServerId}, - {"userId", connectUser.Id}, + {"userId", connectUserId}, {"userType", "Guest"}, {"accessToken", accessToken}, {"requesterUserName", requesterUserName} @@ -446,8 +485,6 @@ namespace MediaBrowser.Server.Implementations.Connect SetServerAccessToken(options); - var result = new UserLinkResult(); - // No need to examine the response using (var stream = (await _httpClient.Post(options).ConfigureAwait(false)).Content) { @@ -461,6 +498,36 @@ namespace MediaBrowser.Server.Implementations.Connect return result; } + private async Task<UserLinkResult> SendNewUserInvitation(string fromName, string email) + { + var url = GetConnectUrl("users/invite"); + + var options = new HttpRequestOptions + { + Url = url, + CancellationToken = CancellationToken.None + }; + + var postData = new Dictionary<string, string> + { + {"email", email}, + {"requesterUserName", fromName} + }; + + options.SetPostData(postData); + + // No need to examine the response + using (var stream = (await _httpClient.Post(options).ConfigureAwait(false)).Content) + { + } + + return new UserLinkResult + { + IsNewUserInvitation = true, + GuestDisplayName = email + }; + } + public Task RemoveConnect(string userId) { var user = GetUser(userId); @@ -586,6 +653,9 @@ namespace MediaBrowser.Server.Implementations.Connect if (connectEntry == null) { + var deleteUser = user.ConnectLinkType.HasValue && + user.ConnectLinkType.Value == UserLinkType.Guest; + user.ConnectUserId = null; user.ConnectAccessKey = null; user.ConnectUserName = null; @@ -593,7 +663,7 @@ namespace MediaBrowser.Server.Implementations.Connect await _userManager.UpdateUser(user).ConfigureAwait(false); - if (user.ConnectLinkType.HasValue && user.ConnectLinkType.Value == UserLinkType.Guest) + if (deleteUser) { _logger.Debug("Deleting guest user {0}", user.Name); await _userManager.DeleteUser(user).ConfigureAwait(false); diff --git a/MediaBrowser.Server.Implementations/Connect/Validator.cs b/MediaBrowser.Server.Implementations/Connect/Validator.cs new file mode 100644 index 000000000..b217da32a --- /dev/null +++ b/MediaBrowser.Server.Implementations/Connect/Validator.cs @@ -0,0 +1,34 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Text.RegularExpressions; +using System.Threading.Tasks; + +namespace MediaBrowser.Server.Implementations.Connect +{ + public static class Validator + { + static Regex ValidEmailRegex = CreateValidEmailRegex(); + + /// <summary> + /// Taken from http://haacked.com/archive/2007/08/21/i-knew-how-to-validate-an-email-address-until-i.aspx + /// </summary> + /// <returns></returns> + private static Regex CreateValidEmailRegex() + { + string validEmailPattern = @"^(?!\.)(""([^""\r\\]|\\[""\r\\])*""|" + + @"([-a-z0-9!#$%&'*+/=?^_`{|}~]|(?<!\.)\.)*)(?<!\.)" + + @"@[a-z0-9][\w\.-]*[a-z0-9]\.[a-z][a-z\.]*[a-z]$"; + + return new Regex(validEmailPattern, RegexOptions.IgnoreCase); + } + + internal static bool EmailIsValid(string emailAddress) + { + bool isValid = ValidEmailRegex.IsMatch(emailAddress); + + return isValid; + } + } +} diff --git a/MediaBrowser.Server.Implementations/HttpServer/HttpListenerHost.cs b/MediaBrowser.Server.Implementations/HttpServer/HttpListenerHost.cs index 0e297816d..98f895616 100644 --- a/MediaBrowser.Server.Implementations/HttpServer/HttpListenerHost.cs +++ b/MediaBrowser.Server.Implementations/HttpServer/HttpListenerHost.cs @@ -205,8 +205,8 @@ namespace MediaBrowser.Server.Implementations.HttpServer HostContext.Config.HandlerFactoryPath = ListenerRequest.GetHandlerPathIfAny(UrlPrefixes.First()); _listener = _supportsNativeWebSocket && NativeWebSocket.IsSupported - //? _listener = new HttpListenerServer(_logger, OnRequestReceived) - ? _listener = new WebSocketSharpListener(_logger, OnRequestReceived) + ? _listener = new HttpListenerServer(_logger, OnRequestReceived) + //? _listener = new WebSocketSharpListener(_logger, OnRequestReceived) : _listener = new WebSocketSharpListener(_logger, OnRequestReceived); _listener.WebSocketHandler = WebSocketHandler; diff --git a/MediaBrowser.Server.Implementations/Library/CoreResolutionIgnoreRule.cs b/MediaBrowser.Server.Implementations/Library/CoreResolutionIgnoreRule.cs index e902b939b..d3d71e0f9 100644 --- a/MediaBrowser.Server.Implementations/Library/CoreResolutionIgnoreRule.cs +++ b/MediaBrowser.Server.Implementations/Library/CoreResolutionIgnoreRule.cs @@ -3,7 +3,6 @@ using MediaBrowser.Controller.Entities; using MediaBrowser.Controller.Library; using MediaBrowser.Controller.Resolvers; using System; -using System.Collections.Generic; using System.IO; using System.Linq; diff --git a/MediaBrowser.Server.Implementations/Library/LibraryManager.cs b/MediaBrowser.Server.Implementations/Library/LibraryManager.cs index 71e1b1087..13ea7fb44 100644 --- a/MediaBrowser.Server.Implementations/Library/LibraryManager.cs +++ b/MediaBrowser.Server.Implementations/Library/LibraryManager.cs @@ -530,20 +530,12 @@ namespace MediaBrowser.Server.Implementations.Library return item; } - public BaseItem ResolvePath(FileSystemInfo fileInfo, Folder parent = null) + public BaseItem ResolvePath(FileSystemInfo fileInfo, Folder parent = null, string collectionType = null) { - return ResolvePath(fileInfo, new DirectoryService(_logger), parent); + return ResolvePath(fileInfo, new DirectoryService(_logger), parent, collectionType); } - /// <summary> - /// Resolves a path into a BaseItem - /// </summary> - /// <param name="fileInfo">The file info.</param> - /// <param name="directoryService">The directory service.</param> - /// <param name="parent">The parent.</param> - /// <returns>BaseItem.</returns> - /// <exception cref="System.ArgumentNullException">fileInfo</exception> - public BaseItem ResolvePath(FileSystemInfo fileInfo, IDirectoryService directoryService, Folder parent = null) + public BaseItem ResolvePath(FileSystemInfo fileInfo, IDirectoryService directoryService, Folder parent = null, string collectionType = null) { if (fileInfo == null) { @@ -554,7 +546,8 @@ namespace MediaBrowser.Server.Implementations.Library { Parent = parent, Path = fileInfo.FullName, - FileInfo = fileInfo + FileInfo = fileInfo, + CollectionType = collectionType }; // Return null if ignore rules deem that we should do so @@ -622,15 +615,7 @@ namespace MediaBrowser.Server.Implementations.Library return !args.ContainsFileSystemEntryByName(".ignore"); } - /// <summary> - /// Resolves a set of files into a list of BaseItem - /// </summary> - /// <typeparam name="T"></typeparam> - /// <param name="files">The files.</param> - /// <param name="directoryService">The directory service.</param> - /// <param name="parent">The parent.</param> - /// <returns>List{``0}.</returns> - public List<T> ResolvePaths<T>(IEnumerable<FileSystemInfo> files, IDirectoryService directoryService, Folder parent) + public List<T> ResolvePaths<T>(IEnumerable<FileSystemInfo> files, IDirectoryService directoryService, Folder parent, string collectionType = null) where T : BaseItem { var list = new List<T>(); @@ -639,7 +624,7 @@ namespace MediaBrowser.Server.Implementations.Library { try { - var item = ResolvePath(f, directoryService, parent) as T; + var item = ResolvePath(f, directoryService, parent, collectionType) as T; if (item != null) { @@ -1190,6 +1175,20 @@ namespace MediaBrowser.Server.Implementations.Library return item; } + public BaseItem GetMemoryItemById(Guid id) + { + if (id == Guid.Empty) + { + throw new ArgumentNullException("id"); + } + + BaseItem item; + + LibraryItemsCache.TryGetValue(id, out item); + + return item; + } + /// <summary> /// Gets the intros. /// </summary> @@ -1497,14 +1496,10 @@ namespace MediaBrowser.Server.Implementations.Library return null; } - var collectionTypes = _userManager.Users - .Select(i => i.RootFolder) - .Distinct() - .SelectMany(i => i.Children) + var collectionTypes = GetUserRootFolder().Children .OfType<ICollectionFolder>() - .Where(i => string.Equals(i.Path, item.Path, StringComparison.OrdinalIgnoreCase) || i.PhysicalLocations.Contains(item.Path)) + .Where(i => !string.IsNullOrEmpty(i.CollectionType) && (string.Equals(i.Path, item.Path, StringComparison.OrdinalIgnoreCase) || i.PhysicalLocations.Contains(item.Path))) .Select(i => i.CollectionType) - .Where(i => !string.IsNullOrEmpty(i)) .Distinct() .ToList(); diff --git a/MediaBrowser.Server.Implementations/Library/Resolvers/Movies/MovieResolver.cs b/MediaBrowser.Server.Implementations/Library/Resolvers/Movies/MovieResolver.cs index 7f15dce2d..231b807d8 100644 --- a/MediaBrowser.Server.Implementations/Library/Resolvers/Movies/MovieResolver.cs +++ b/MediaBrowser.Server.Implementations/Library/Resolvers/Movies/MovieResolver.cs @@ -82,29 +82,29 @@ namespace MediaBrowser.Server.Implementations.Library.Resolvers.Movies { if (string.Equals(collectionType, CollectionType.Trailers, StringComparison.OrdinalIgnoreCase)) { - return FindMovie<Trailer>(args.Path, args.Parent, args.FileSystemChildren.ToList(), args.DirectoryService, false, false); + return FindMovie<Trailer>(args.Path, args.Parent, args.FileSystemChildren.ToList(), args.DirectoryService, false, false, collectionType); } if (string.Equals(collectionType, CollectionType.MusicVideos, StringComparison.OrdinalIgnoreCase)) { - return FindMovie<MusicVideo>(args.Path, args.Parent, args.FileSystemChildren.ToList(), args.DirectoryService, false, false); + return FindMovie<MusicVideo>(args.Path, args.Parent, args.FileSystemChildren.ToList(), args.DirectoryService, false, false, collectionType); } if (string.Equals(collectionType, CollectionType.AdultVideos, StringComparison.OrdinalIgnoreCase)) { - return FindMovie<Video>(args.Path, args.Parent, args.FileSystemChildren.ToList(), args.DirectoryService, true, false); + return FindMovie<Video>(args.Path, args.Parent, args.FileSystemChildren.ToList(), args.DirectoryService, true, false, collectionType); } if (string.Equals(collectionType, CollectionType.HomeVideos, StringComparison.OrdinalIgnoreCase)) { - return FindMovie<Video>(args.Path, args.Parent, args.FileSystemChildren.ToList(), args.DirectoryService, true, false); + return FindMovie<Video>(args.Path, args.Parent, args.FileSystemChildren.ToList(), args.DirectoryService, true, false, collectionType); } if (string.IsNullOrEmpty(collectionType) || string.Equals(collectionType, CollectionType.Movies, StringComparison.OrdinalIgnoreCase) || string.Equals(collectionType, CollectionType.BoxSets, StringComparison.OrdinalIgnoreCase)) { - return FindMovie<Movie>(args.Path, args.Parent, args.FileSystemChildren.ToList(), args.DirectoryService, true, true); + return FindMovie<Movie>(args.Path, args.Parent, args.FileSystemChildren.ToList(), args.DirectoryService, true, true, collectionType); } return null; @@ -190,7 +190,7 @@ namespace MediaBrowser.Server.Implementations.Library.Resolvers.Movies /// <param name="directoryService">The directory service.</param> /// <param name="supportMultiFileItems">if set to <c>true</c> [support multi file items].</param> /// <returns>Movie.</returns> - private T FindMovie<T>(string path, Folder parent, List<FileSystemInfo> fileSystemEntries, IDirectoryService directoryService, bool supportMultiFileItems, bool supportsMultipleSources) + private T FindMovie<T>(string path, Folder parent, List<FileSystemInfo> fileSystemEntries, IDirectoryService directoryService, bool supportMultiFileItems, bool supportsMultipleSources, string collectionType) where T : Video, new() { var movies = new List<T>(); @@ -239,7 +239,8 @@ namespace MediaBrowser.Server.Implementations.Library.Resolvers.Movies { FileInfo = child, Path = child.FullName, - Parent = parent + Parent = parent, + CollectionType = collectionType }; var item = ResolveVideo<T>(childArgs); diff --git a/MediaBrowser.Server.Implementations/Localization/JavaScript/javascript.json b/MediaBrowser.Server.Implementations/Localization/JavaScript/javascript.json index 929c3143d..21c8ba889 100644 --- a/MediaBrowser.Server.Implementations/Localization/JavaScript/javascript.json +++ b/MediaBrowser.Server.Implementations/Localization/JavaScript/javascript.json @@ -75,7 +75,7 @@ "ButtonClose": "Close", "LabelAllPlaysSentToPlayer": "All plays will be sent to the selected player.", "MessageInvalidUser": "Invalid username or password. Please try again.", - "HeaderLoginFailure": "Login Failure", + "HeaderLoginFailure": "Login Failure", "HeaderAllRecordings": "All Recordings", "RecommendationBecauseYouLike": "Because you like {0}", "RecommendationBecauseYouWatched": "Because you watched {0}", @@ -613,5 +613,8 @@ "LabelEnableCameraUploadForHelp": "Uploads will occur automatically in the background when signed into Media Browser.", "ErrorMessageStartHourGreaterThanEnd": "End time must be greater than the start time.", "ButtonLibraryAccess": "Library access", - "ButtonParentalControl": "Parental control" + "ButtonParentalControl": "Parental control", + "HeaderInvitationSent": "Invitation Sent", + "MessageInvitationSentToUser": "An email has been sent to {0}, inviting them to accept your sharing invitation.", + "MessageInvitationSentToNewUser": "An email has been sent to {0} inviting them to sign up with Media Browser." } diff --git a/MediaBrowser.Server.Implementations/Localization/Server/server.json b/MediaBrowser.Server.Implementations/Localization/Server/server.json index 239792444..3231593d4 100644 --- a/MediaBrowser.Server.Implementations/Localization/Server/server.json +++ b/MediaBrowser.Server.Implementations/Localization/Server/server.json @@ -1166,6 +1166,7 @@ "OptionSaveMetadataAsHidden": "Save metadata and images as hidden files", "LabelExtractChaptersDuringLibraryScan": "Extract chapter images during the library scan", "LabelExtractChaptersDuringLibraryScanHelp": "If enabled, chapter images will be extracted when videos are imported during the library scan. If disabled they will be extracted during the chapter images scheduled task, allowing the regular library scan to complete faster.", + "LabelConnectGuestUserName": "Their Media Browser username or email address:", "LabelConnectUserName": "Media Browser username/email:", "LabelConnectUserNameHelp": "Connect this user to a Media Browser account to enable easy sign-in access from Media Browser any app without having to know the server ip address.", "ButtonLearnMoreAboutMediaBrowserConnect": "Learn more about Media Browser Connect", @@ -1229,7 +1230,7 @@ "LabelCustomDeviceDisplayName": "Display name:", "LabelCustomDeviceDisplayNameHelp": "Supply a custom display name or leave empty to use the name reported by the device.", "HeaderInviteUser": "Invite User", - "LabelConnectInviteUserHelp": "This is the username or email that your friend uses to sign in to the Media Browser website.", + "LabelConnectGuestUserNameHelp": "This is the username that your friend uses to sign in to the Media Browser website, or their email address.", "HeaderInviteUserHelp": "Sharing your media with friends is easier than ever before with Media Browser Connect.", "ButtonSendInvitation": "Send Invitation", "HeaderGuests": "Guests", diff --git a/MediaBrowser.Server.Implementations/MediaBrowser.Server.Implementations.csproj b/MediaBrowser.Server.Implementations/MediaBrowser.Server.Implementations.csproj index 474ae5beb..38d5eb072 100644 --- a/MediaBrowser.Server.Implementations/MediaBrowser.Server.Implementations.csproj +++ b/MediaBrowser.Server.Implementations/MediaBrowser.Server.Implementations.csproj @@ -119,6 +119,7 @@ <Compile Include="Connect\ConnectData.cs" /> <Compile Include="Connect\ConnectManager.cs" /> <Compile Include="Connect\Responses.cs" /> + <Compile Include="Connect\Validator.cs" /> <Compile Include="Devices\DeviceManager.cs" /> <Compile Include="Devices\DeviceRepository.cs" /> <Compile Include="Devices\CameraUploadsFolder.cs" /> diff --git a/MediaBrowser.Server.Implementations/Persistence/SqliteItemRepository.cs b/MediaBrowser.Server.Implementations/Persistence/SqliteItemRepository.cs index 70362654e..cd7928290 100644 --- a/MediaBrowser.Server.Implementations/Persistence/SqliteItemRepository.cs +++ b/MediaBrowser.Server.Implementations/Persistence/SqliteItemRepository.cs @@ -257,7 +257,7 @@ namespace MediaBrowser.Server.Implementations.Persistence _writeLock.Release(); } } - + /// <summary> /// Internal retrieve from items or users table /// </summary> @@ -473,6 +473,34 @@ namespace MediaBrowser.Server.Implementations.Persistence } } + public IEnumerable<BaseItem> GetChildrenItems(Guid parentId) + { + if (parentId == Guid.Empty) + { + throw new ArgumentNullException("parentId"); + } + + using (var cmd = _connection.CreateCommand()) + { + cmd.CommandText = "select type,data from TypedBaseItems where guid in (select ItemId from ChildrenIds where ParentId = @ParentId)"; + + cmd.Parameters.Add(cmd, "@ParentId", DbType.Guid).Value = parentId; + + using (var reader = cmd.ExecuteReader(CommandBehavior.SequentialAccess | CommandBehavior.SingleResult)) + { + while (reader.Read()) + { + var item = GetItem(reader); + + if (item != null) + { + yield return item; + } + } + } + } + } + public IEnumerable<BaseItem> GetItemsOfType(Type type) { if (type == null) diff --git a/MediaBrowser.Server.Implementations/Persistence/SqliteMediaStreamsRepository.cs b/MediaBrowser.Server.Implementations/Persistence/SqliteMediaStreamsRepository.cs index 4bcd4a46d..e9d7f44ec 100644 --- a/MediaBrowser.Server.Implementations/Persistence/SqliteMediaStreamsRepository.cs +++ b/MediaBrowser.Server.Implementations/Persistence/SqliteMediaStreamsRepository.cs @@ -40,7 +40,7 @@ namespace MediaBrowser.Server.Implementations.Persistence // Add PixelFormat column - createTableCommand += "(ItemId GUID, StreamIndex INT, StreamType TEXT, Codec TEXT, Language TEXT, ChannelLayout TEXT, Profile TEXT, AspectRatio TEXT, Path TEXT, IsInterlaced BIT, BitRate INT NULL, Channels INT NULL, SampleRate INT NULL, IsDefault BIT, IsForced BIT, IsExternal BIT, Height INT NULL, Width INT NULL, AverageFrameRate FLOAT NULL, RealFrameRate FLOAT NULL, Level FLOAT NULL, PixelFormat TEXT, BitDepth INT NULL, IsAnamorphic BIT NULL, RefFrames INT NULL, PRIMARY KEY (ItemId, StreamIndex))"; + createTableCommand += "(ItemId GUID, StreamIndex INT, StreamType TEXT, Codec TEXT, Language TEXT, ChannelLayout TEXT, Profile TEXT, AspectRatio TEXT, Path TEXT, IsInterlaced BIT, BitRate INT NULL, Channels INT NULL, SampleRate INT NULL, IsDefault BIT, IsForced BIT, IsExternal BIT, Height INT NULL, Width INT NULL, AverageFrameRate FLOAT NULL, RealFrameRate FLOAT NULL, Level FLOAT NULL, PixelFormat TEXT, BitDepth INT NULL, IsAnamorphic BIT NULL, RefFrames INT NULL, IsCabac BIT NULL, PRIMARY KEY (ItemId, StreamIndex))"; string[] queries = { @@ -59,6 +59,7 @@ namespace MediaBrowser.Server.Implementations.Persistence AddPixelFormatColumnCommand(); AddBitDepthCommand(); AddIsAnamorphicColumn(); + AddIsCabacColumn(); AddRefFramesCommand(); PrepareStatements(); @@ -159,6 +160,37 @@ namespace MediaBrowser.Server.Implementations.Persistence _connection.RunQueries(new[] { builder.ToString() }, _logger); } + private void AddIsCabacColumn() + { + using (var cmd = _connection.CreateCommand()) + { + cmd.CommandText = "PRAGMA table_info(mediastreams)"; + + using (var reader = cmd.ExecuteReader(CommandBehavior.SequentialAccess | CommandBehavior.SingleResult)) + { + while (reader.Read()) + { + if (!reader.IsDBNull(1)) + { + var name = reader.GetString(1); + + if (string.Equals(name, "IsCabac", StringComparison.OrdinalIgnoreCase)) + { + return; + } + } + } + } + } + + var builder = new StringBuilder(); + + builder.AppendLine("alter table mediastreams"); + builder.AppendLine("add column IsCabac BIT NULL"); + + _connection.RunQueries(new[] { builder.ToString() }, _logger); + } + private void AddIsAnamorphicColumn() { using (var cmd = _connection.CreateCommand()) @@ -216,7 +248,8 @@ namespace MediaBrowser.Server.Implementations.Persistence "PixelFormat", "BitDepth", "IsAnamorphic", - "RefFrames" + "RefFrames", + "IsCabac" }; /// <summary> @@ -395,6 +428,11 @@ namespace MediaBrowser.Server.Implementations.Persistence item.RefFrames = reader.GetInt32(24); } + if (!reader.IsDBNull(25)) + { + item.IsCabac = reader.GetBoolean(25); + } + return item; } @@ -460,6 +498,7 @@ namespace MediaBrowser.Server.Implementations.Persistence _saveStreamCommand.GetParameter(22).Value = stream.BitDepth; _saveStreamCommand.GetParameter(23).Value = stream.IsAnamorphic; _saveStreamCommand.GetParameter(24).Value = stream.RefFrames; + _saveStreamCommand.GetParameter(25).Value = stream.IsCabac; _saveStreamCommand.Transaction = transaction; _saveStreamCommand.ExecuteNonQuery(); diff --git a/MediaBrowser.Server.Implementations/Session/SessionManager.cs b/MediaBrowser.Server.Implementations/Session/SessionManager.cs index a0cd60067..ac8068744 100644 --- a/MediaBrowser.Server.Implementations/Session/SessionManager.cs +++ b/MediaBrowser.Server.Implementations/Session/SessionManager.cs @@ -359,6 +359,7 @@ namespace MediaBrowser.Server.Implementations.Session session.NowPlayingItem = info.Item; session.LastActivityDate = DateTime.UtcNow; + session.LastPlaybackCheckIn = DateTime.UtcNow; session.PlayState.IsPaused = info.IsPaused; session.PlayState.PositionTicks = info.PositionTicks; @@ -498,6 +499,65 @@ namespace MediaBrowser.Server.Implementations.Session return users; } + private Timer _idleTimer; + + private void StartIdleCheckTimer() + { + if (_idleTimer == null) + { + _idleTimer = new Timer(CheckForIdlePlayback, null, TimeSpan.FromMinutes(5), TimeSpan.FromMinutes(5)); + } + } + private void StopIdleCheckTimer() + { + if (_idleTimer != null) + { + _idleTimer.Dispose(); + _idleTimer = null; + } + } + + private async void CheckForIdlePlayback(object state) + { + var playingSessions = Sessions.Where(i => i.NowPlayingItem != null) + .ToList(); + + if (playingSessions.Count > 0) + { + var idle = playingSessions + .Where(i => (DateTime.UtcNow - i.LastPlaybackCheckIn).TotalMinutes > 5) + .ToList(); + + foreach (var session in idle) + { + _logger.Debug("Session {0} has gone idle while playing", session.Id); + + try + { + await OnPlaybackStopped(new PlaybackStopInfo + { + Item = session.NowPlayingItem, + ItemId = (session.NowPlayingItem == null ? null : session.NowPlayingItem.Id), + SessionId = session.Id, + MediaSourceId = (session.PlayState == null ? null : session.PlayState.MediaSourceId) + }); + } + catch (Exception ex) + { + _logger.Debug("Error calling OnPlaybackStopped", ex); + } + } + + playingSessions = Sessions.Where(i => i.NowPlayingItem != null) + .ToList(); + } + + if (playingSessions.Count == 0) + { + StopIdleCheckTimer(); + } + } + /// <summary> /// Used to report that playback has started for an item /// </summary> @@ -553,6 +613,8 @@ namespace MediaBrowser.Server.Implementations.Session }, _logger); await SendPlaybackStartNotification(session, CancellationToken.None).ConfigureAwait(false); + + StartIdleCheckTimer(); } /// <summary> @@ -623,6 +685,8 @@ namespace MediaBrowser.Server.Implementations.Session DeviceId = session.DeviceId }, _logger); + + StartIdleCheckTimer(); } private async Task OnPlaybackProgress(Guid userId, string userDataKey, BaseItem item, long? positionTicks) |
