diff options
| author | Luke Pulverenti <luke.pulverenti@gmail.com> | 2016-06-03 20:15:14 -0400 |
|---|---|---|
| committer | Luke Pulverenti <luke.pulverenti@gmail.com> | 2016-06-03 20:15:14 -0400 |
| commit | ddb6ea6f0576a6ba9c6050cc0799ac6b0e3c2fa8 (patch) | |
| tree | 3a89421939b5c69ebe122396f4f2af92da49c893 /MediaBrowser.Server.Implementations | |
| parent | 7cf424303b95d589a7ad318767139106db5f5363 (diff) | |
rework user data
Diffstat (limited to 'MediaBrowser.Server.Implementations')
3 files changed, 90 insertions, 96 deletions
diff --git a/MediaBrowser.Server.Implementations/Library/UserDataManager.cs b/MediaBrowser.Server.Implementations/Library/UserDataManager.cs index afbce87a9..c2606dc4b 100644 --- a/MediaBrowser.Server.Implementations/Library/UserDataManager.cs +++ b/MediaBrowser.Server.Implementations/Library/UserDataManager.cs @@ -23,7 +23,8 @@ namespace MediaBrowser.Server.Implementations.Library { public event EventHandler<UserDataSaveEventArgs> UserDataSaved; - private readonly Dictionary<string, UserItemData> _userData = new Dictionary<string, UserItemData>(StringComparer.OrdinalIgnoreCase); + private readonly ConcurrentDictionary<string, UserItemData> _userData = + new ConcurrentDictionary<string, UserItemData>(StringComparer.OrdinalIgnoreCase); private readonly ILogger _logger; private readonly IServerConfigurationManager _config; @@ -64,13 +65,6 @@ namespace MediaBrowser.Server.Implementations.Library try { await Repository.SaveUserData(userId, key, userData, cancellationToken).ConfigureAwait(false); - - var newValue = userData; - - lock (_userData) - { - _userData[GetCacheKey(userId, key)] = newValue; - } } catch (Exception ex) { @@ -80,6 +74,9 @@ namespace MediaBrowser.Server.Implementations.Library } } + var cacheKey = GetCacheKey(userId, item.Id); + _userData.AddOrUpdate(cacheKey, userData, (k, v) => userData); + EventHelper.FireEventIfNotNull(UserDataSaved, this, new UserDataSaveEventArgs { Keys = keys, @@ -122,7 +119,7 @@ namespace MediaBrowser.Server.Implementations.Library throw; } - + } /// <summary> @@ -140,7 +137,7 @@ namespace MediaBrowser.Server.Implementations.Library return Repository.GetAllUserData(userId); } - public UserItemData GetUserData(Guid userId, List<string> keys) + public UserItemData GetUserData(Guid userId, Guid itemId, List<string> keys) { if (userId == Guid.Empty) { @@ -150,26 +147,23 @@ namespace MediaBrowser.Server.Implementations.Library { throw new ArgumentNullException("keys"); } - - lock (_userData) + if (keys.Count == 0) { - foreach (var key in keys) - { - var cacheKey = GetCacheKey(userId, key); - UserItemData value; - if (_userData.TryGetValue(cacheKey, out value)) - { - return value; - } + throw new ArgumentException("UserData keys cannot be empty."); + } - value = Repository.GetUserData(userId, key); + var cacheKey = GetCacheKey(userId, itemId); - if (value != null) - { - _userData[cacheKey] = value; - return value; - } - } + return _userData.GetOrAdd(cacheKey, k => GetUserDataInternal(userId, keys)); + } + + private UserItemData GetUserDataInternal(Guid userId, List<string> keys) + { + var userData = Repository.GetUserData(userId, keys); + + if (userData != null) + { + return userData; } if (keys.Count > 0) @@ -185,56 +179,12 @@ namespace MediaBrowser.Server.Implementations.Library } /// <summary> - /// Gets the user data. - /// </summary> - /// <param name="userId">The user id.</param> - /// <param name="key">The key.</param> - /// <returns>Task{UserItemData}.</returns> - public UserItemData GetUserData(Guid userId, string key) - { - if (userId == Guid.Empty) - { - throw new ArgumentNullException("userId"); - } - if (string.IsNullOrEmpty(key)) - { - throw new ArgumentNullException("key"); - } - - lock (_userData) - { - var cacheKey = GetCacheKey(userId, key); - UserItemData value; - if (_userData.TryGetValue(cacheKey, out value)) - { - return value; - } - - value = Repository.GetUserData(userId, key); - - if (value == null) - { - value = new UserItemData - { - UserId = userId, - Key = key - }; - } - - _userData[cacheKey] = value; - return value; - } - } - - /// <summary> /// Gets the internal key. /// </summary> - /// <param name="userId">The user id.</param> - /// <param name="key">The key.</param> /// <returns>System.String.</returns> - private string GetCacheKey(Guid userId, string key) + private string GetCacheKey(Guid userId, Guid itemId) { - return userId + key; + return userId.ToString("N") + itemId.ToString("N"); } public UserItemData GetUserData(IHasUserData user, IHasUserData item) @@ -249,7 +199,7 @@ namespace MediaBrowser.Server.Implementations.Library public UserItemData GetUserData(Guid userId, IHasUserData item) { - return GetUserData(userId, item.GetUserDataKeys()); + return GetUserData(userId, item.Id, item.GetUserDataKeys()); } public UserItemDataDto GetUserDataDto(IHasUserData item, User user) diff --git a/MediaBrowser.Server.Implementations/Persistence/SqliteUserDataRepository.cs b/MediaBrowser.Server.Implementations/Persistence/SqliteUserDataRepository.cs index 7f3b32e06..bfdb9e0c7 100644 --- a/MediaBrowser.Server.Implementations/Persistence/SqliteUserDataRepository.cs +++ b/MediaBrowser.Server.Implementations/Persistence/SqliteUserDataRepository.cs @@ -5,7 +5,9 @@ using MediaBrowser.Model.Logging; using System; using System.Collections.Generic; using System.Data; +using System.Globalization; using System.IO; +using System.Text; using System.Threading; using System.Threading.Tasks; @@ -300,6 +302,52 @@ namespace MediaBrowser.Server.Implementations.Persistence } } + public UserItemData GetUserData(Guid userId, List<string> keys) + { + if (userId == Guid.Empty) + { + throw new ArgumentNullException("userId"); + } + if (keys == null) + { + throw new ArgumentNullException("keys"); + } + + using (var cmd = _connection.CreateCommand()) + { + var index = 0; + var excludeIds = new List<string>(); + var builder = new StringBuilder(); + foreach (var key in keys) + { + var paramName = "@Key" + index; + excludeIds.Add("Key =" + paramName); + cmd.Parameters.Add(cmd, paramName, DbType.String).Value = key; + builder.Append(" WHEN Key=" + paramName + " THEN " + index); + index++; + } + + var keyText = string.Join(" OR ", excludeIds.ToArray()); + + cmd.CommandText = "select key,userid,rating,played,playCount,isFavorite,playbackPositionTicks,lastPlayedDate,AudioStreamIndex,SubtitleStreamIndex from userdata where userId=@userId AND (" + keyText + ") "; + + cmd.CommandText += " ORDER BY (Case " + builder + " Else " + keys.Count.ToString(CultureInfo.InvariantCulture) + " End )"; + cmd.CommandText += " LIMIT 1"; + + cmd.Parameters.Add(cmd, "@userId", DbType.Guid).Value = userId; + + using (var reader = cmd.ExecuteReader(CommandBehavior.SequentialAccess | CommandBehavior.SingleResult | CommandBehavior.SingleRow)) + { + if (reader.Read()) + { + return ReadRow(reader); + } + } + + return null; + } + } + /// <summary> /// Return all user-data associated with the given user /// </summary> diff --git a/MediaBrowser.Server.Implementations/TV/TVSeriesManager.cs b/MediaBrowser.Server.Implementations/TV/TVSeriesManager.cs index ec91dc1b7..6019d64b4 100644 --- a/MediaBrowser.Server.Implementations/TV/TVSeriesManager.cs +++ b/MediaBrowser.Server.Implementations/TV/TVSeriesManager.cs @@ -111,24 +111,6 @@ namespace MediaBrowser.Server.Implementations.TV .Select(i => GetNextUp(i, currentUser)) // Include if an episode was found, and either the series is not unwatched or the specific series was requested .Where(i => i.Item1 != null && (!i.Item3 || !string.IsNullOrWhiteSpace(request.SeriesId))) - //.OrderByDescending(i => - //{ - // var episode = i.Item1; - - // var seriesUserData = _userDataManager.GetUserData(user, episode.Series); - - // if (seriesUserData.IsFavorite) - // { - // return 2; - // } - - // if (seriesUserData.Likes.HasValue) - // { - // return seriesUserData.Likes.Value ? 1 : -1; - // } - - // return 0; - //}) .OrderByDescending(i => i.Item2) .ThenByDescending(i => i.Item1.PremiereDate ?? DateTime.MinValue) .Select(i => i.Item1); @@ -143,9 +125,8 @@ namespace MediaBrowser.Server.Implementations.TV private Tuple<Episode, DateTime, bool> GetNextUp(Series series, User user) { // Get them in display order, then reverse - var allEpisodes = series.GetSeasons(user, true, true) - .Where(i => !i.IndexNumber.HasValue || i.IndexNumber.Value != 0) - .SelectMany(i => i.GetEpisodes(user)) + var allEpisodes = series.GetEpisodes(user, true, true) + .Where(i => !i.ParentIndexNumber.HasValue || i.ParentIndexNumber.Value != 0) .Reverse() .ToList(); @@ -155,6 +136,8 @@ namespace MediaBrowser.Server.Implementations.TV var includeMissing = user.Configuration.DisplayMissingEpisodes; + var unplayedEpisodes = new List<Episode>(); + // Go back starting with the most recent episodes foreach (var episode in allEpisodes) { @@ -172,6 +155,8 @@ namespace MediaBrowser.Server.Implementations.TV } else { + unplayedEpisodes.Add(episode); + if (!episode.IsVirtualUnaired && (includeMissing || !episode.IsMissingEpisode)) { nextUp = episode; @@ -184,7 +169,18 @@ namespace MediaBrowser.Server.Implementations.TV return new Tuple<Episode, DateTime, bool>(nextUp, lastWatchedDate, false); } - var firstEpisode = allEpisodes.LastOrDefault(i => !i.IsVirtualUnaired && (includeMissing || !i.IsMissingEpisode) && !i.IsPlayed(user)); + Episode firstEpisode = null; + // Find the first unplayed episode. Start from the back of the list since they're in reverse order + for (var i = unplayedEpisodes.Count - 1; i >= 0; i--) + { + var unplayedEpisode = unplayedEpisodes[i]; + + if (!unplayedEpisode.IsVirtualUnaired && (includeMissing || !unplayedEpisode.IsMissingEpisode)) + { + firstEpisode = unplayedEpisode; + break; + } + } // Return the first episode return new Tuple<Episode, DateTime, bool>(firstEpisode, DateTime.MinValue, true); |
