diff --git a/MediaBrowser.Api/MediaBrowser.Api.csproj b/MediaBrowser.Api/MediaBrowser.Api.csproj
index c95df7db31..6e214f960c 100644
--- a/MediaBrowser.Api/MediaBrowser.Api.csproj
+++ b/MediaBrowser.Api/MediaBrowser.Api.csproj
@@ -123,7 +123,6 @@
-
diff --git a/MediaBrowser.Api/UserLibrary/ItemByNameUserDataService.cs b/MediaBrowser.Api/UserLibrary/ItemByNameUserDataService.cs
deleted file mode 100644
index 1c32082164..0000000000
--- a/MediaBrowser.Api/UserLibrary/ItemByNameUserDataService.cs
+++ /dev/null
@@ -1,264 +0,0 @@
-using MediaBrowser.Controller.Dto;
-using MediaBrowser.Controller.Library;
-using MediaBrowser.Model.Dto;
-using MediaBrowser.Model.Entities;
-using ServiceStack;
-using System;
-using System.Threading;
-using System.Threading.Tasks;
-using ServiceStack.Text.Controller;
-
-namespace MediaBrowser.Api.UserLibrary
-{
- ///
- /// Class MarkItemByNameFavorite
- ///
- [Route("/Users/{UserId}/Favorites/Artists/{Name}", "POST")]
- [Route("/Users/{UserId}/Favorites/Persons/{Name}", "POST")]
- [Route("/Users/{UserId}/Favorites/Studios/{Name}", "POST")]
- [Route("/Users/{UserId}/Favorites/Genres/{Name}", "POST")]
- [Route("/Users/{UserId}/Favorites/MusicGenres/{Name}", "POST")]
- [Route("/Users/{UserId}/Favorites/GameGenres/{Name}", "POST")]
- [Api(Description = "Marks something as a favorite")]
- public class MarkItemByNameFavorite : IReturn
- {
- ///
- /// Gets or sets the user id.
- ///
- /// The user id.
- [ApiMember(Name = "UserId", Description = "User Id", IsRequired = true, DataType = "string", ParameterType = "path", Verb = "POST")]
- public Guid UserId { get; set; }
-
- ///
- /// Gets or sets the name.
- ///
- /// The name.
- [ApiMember(Name = "Name", Description = "The name", IsRequired = true, DataType = "string", ParameterType = "path", Verb = "POST")]
- public string Name { get; set; }
- }
-
- ///
- /// Class UnmarkItemByNameFavorite
- ///
- [Route("/Users/{UserId}/Favorites/Artists/{Name}", "DELETE")]
- [Route("/Users/{UserId}/Favorites/Persons/{Name}", "DELETE")]
- [Route("/Users/{UserId}/Favorites/Studios/{Name}", "DELETE")]
- [Route("/Users/{UserId}/Favorites/Genres/{Name}", "DELETE")]
- [Route("/Users/{UserId}/Favorites/MusicGenres/{Name}", "DELETE")]
- [Route("/Users/{UserId}/Favorites/GameGenres/{Name}", "DELETE")]
- [Api(Description = "Unmarks something as a favorite")]
- public class UnmarkItemByNameFavorite : IReturn
- {
- ///
- /// Gets or sets the user id.
- ///
- /// The user id.
- [ApiMember(Name = "UserId", Description = "User Id", IsRequired = true, DataType = "string", ParameterType = "path", Verb = "DELETE")]
- public Guid UserId { get; set; }
-
- ///
- /// Gets or sets the name.
- ///
- /// The name.
- [ApiMember(Name = "Name", Description = "The name", IsRequired = true, DataType = "string", ParameterType = "path", Verb = "DELETE")]
- public string Name { get; set; }
- }
-
- ///
- /// Class UpdateItemByNameRating
- ///
- [Route("/Users/{UserId}/Ratings/Artists/{Name}", "POST")]
- [Route("/Users/{UserId}/Ratings/Persons/{Name}", "POST")]
- [Route("/Users/{UserId}/Ratings/Studios/{Name}", "POST")]
- [Route("/Users/{UserId}/Ratings/Genres/{Name}", "POST")]
- [Route("/Users/{UserId}/Ratings/MusicGenres/{Name}", "POST")]
- [Api(Description = "Updates a user's rating for an item")]
- public class UpdateItemByNameRating : IReturn
- {
- ///
- /// Gets or sets the user id.
- ///
- /// The user id.
- [ApiMember(Name = "UserId", Description = "User Id", IsRequired = true, DataType = "string", ParameterType = "path", Verb = "POST")]
- public Guid UserId { get; set; }
-
- ///
- /// Gets or sets the name.
- ///
- /// The name.
- [ApiMember(Name = "Name", Description = "The name", IsRequired = true, DataType = "string", ParameterType = "path", Verb = "POST")]
- public string Name { get; set; }
-
- ///
- /// Gets or sets a value indicating whether this is likes.
- ///
- /// true if likes; otherwise, false.
- [ApiMember(Name = "Likes", Description = "Whether the user likes the item or not. true/false", IsRequired = true, DataType = "boolean", ParameterType = "query", Verb = "POST")]
- public bool Likes { get; set; }
- }
-
- ///
- /// Class DeleteItemByNameRating
- ///
- [Route("/Users/{UserId}/Ratings/Artists/{Name}", "DELETE")]
- [Route("/Users/{UserId}/Ratings/Persons/{Name}", "DELETE")]
- [Route("/Users/{UserId}/Ratings/Studios/{Name}", "DELETE")]
- [Route("/Users/{UserId}/Ratings/Genres/{Name}", "DELETE")]
- [Route("/Users/{UserId}/Ratings/MusicGenres/{Name}", "DELETE")]
- [Route("/Users/{UserId}/Ratings/GameGenres/{Name}", "DELETE")]
- [Api(Description = "Deletes a user's saved personal rating for an item")]
- public class DeleteItemByNameRating : IReturn
- {
- ///
- /// Gets or sets the user id.
- ///
- /// The user id.
- [ApiMember(Name = "UserId", Description = "User Id", IsRequired = true, DataType = "string", ParameterType = "path", Verb = "DELETE")]
- public Guid UserId { get; set; }
-
- ///
- /// Gets or sets the name.
- ///
- /// The name.
- [ApiMember(Name = "Name", Description = "The item name (genre, person, year, studio, artist)", IsRequired = true, DataType = "string", ParameterType = "path", Verb = "DELETE")]
- public string Name { get; set; }
- }
-
- ///
- /// Class ItemByNameUserDataService
- ///
- public class ItemByNameUserDataService : BaseApiService
- {
- ///
- /// The user data repository
- ///
- protected readonly IUserDataManager UserDataRepository;
-
- ///
- /// The library manager
- ///
- protected readonly ILibraryManager LibraryManager;
- private readonly IDtoService _dtoService;
-
- ///
- /// Initializes a new instance of the class.
- ///
- /// The user data repository.
- /// The library manager.
- public ItemByNameUserDataService(IUserDataManager userDataRepository, ILibraryManager libraryManager, IDtoService dtoService)
- {
- UserDataRepository = userDataRepository;
- LibraryManager = libraryManager;
- _dtoService = dtoService;
- }
-
- ///
- /// Posts the specified request.
- ///
- /// The request.
- public object Post(MarkItemByNameFavorite request)
- {
- var pathInfo = PathInfo.Parse(Request.PathInfo);
- var type = pathInfo.GetArgumentValue(3);
-
- var task = MarkFavorite(request.UserId, type, request.Name, true);
-
- return ToOptimizedResult(task.Result);
- }
-
- ///
- /// Posts the specified request.
- ///
- /// The request.
- public object Post(UpdateItemByNameRating request)
- {
- var pathInfo = PathInfo.Parse(Request.PathInfo);
- var type = pathInfo.GetArgumentValue(3);
-
- var task = MarkLike(request.UserId, type, request.Name, request.Likes);
-
- return ToOptimizedResult(task.Result);
- }
-
- ///
- /// Deletes the specified request.
- ///
- /// The request.
- public object Delete(UnmarkItemByNameFavorite request)
- {
- var pathInfo = PathInfo.Parse(Request.PathInfo);
- var type = pathInfo.GetArgumentValue(3);
-
- var task = MarkFavorite(request.UserId, type, request.Name, false);
-
- return ToOptimizedResult(task.Result);
- }
-
- ///
- /// Deletes the specified request.
- ///
- /// The request.
- public object Delete(DeleteItemByNameRating request)
- {
- var pathInfo = PathInfo.Parse(Request.PathInfo);
- var type = pathInfo.GetArgumentValue(3);
-
- var task = MarkLike(request.UserId, type, request.Name, null);
-
- return ToOptimizedResult(task.Result);
- }
-
- ///
- /// Marks the favorite.
- ///
- /// The user id.
- /// The type.
- /// The name.
- /// if set to true [is favorite].
- /// Task.
- protected async Task MarkFavorite(Guid userId, string type, string name, bool isFavorite)
- {
- var item = GetItemByName(name, type, LibraryManager);
-
- var key = item.GetUserDataKey();
-
- // Get the user data for this item
- var data = UserDataRepository.GetUserData(userId, key);
-
- // Set favorite status
- data.IsFavorite = isFavorite;
-
- await UserDataRepository.SaveUserData(userId, item, data, UserDataSaveReason.UpdateUserRating, CancellationToken.None).ConfigureAwait(false);
-
- data = UserDataRepository.GetUserData(userId, key);
-
- return _dtoService.GetUserItemDataDto(data);
- }
-
- ///
- /// Marks the like.
- ///
- /// The user id.
- /// The type.
- /// The name.
- /// if set to true [likes].
- /// Task.
- protected async Task MarkLike(Guid userId, string type, string name, bool? likes)
- {
- var item = GetItemByName(name, type, LibraryManager);
-
- var key = item.GetUserDataKey();
-
- // Get the user data for this item
- var data = UserDataRepository.GetUserData(userId, key);
-
- data.Likes = likes;
-
- await UserDataRepository.SaveUserData(userId, item, data, UserDataSaveReason.UpdateUserRating, CancellationToken.None).ConfigureAwait(false);
-
- data = UserDataRepository.GetUserData(userId, key);
-
- return _dtoService.GetUserItemDataDto(data);
- }
- }
-}
diff --git a/MediaBrowser.Controller/Entities/Folder.cs b/MediaBrowser.Controller/Entities/Folder.cs
index 6472b988a2..b56abcc805 100644
--- a/MediaBrowser.Controller/Entities/Folder.cs
+++ b/MediaBrowser.Controller/Entities/Folder.cs
@@ -424,7 +424,7 @@ namespace MediaBrowser.Controller.Entities
{
BaseItem currentChild;
- if (currentChildren.TryGetValue(child.Id, out currentChild))
+ if (currentChildren.TryGetValue(child.Id, out currentChild) && child.IsInMixedFolder == currentChild.IsInMixedFolder)
{
var currentChildLocationType = currentChild.LocationType;
if (currentChildLocationType != LocationType.Remote &&
@@ -433,7 +433,6 @@ namespace MediaBrowser.Controller.Entities
currentChild.DateModified = child.DateModified;
}
- currentChild.IsInMixedFolder = child.IsInMixedFolder;
currentChild.IsOffline = false;
}
else
diff --git a/MediaBrowser.Model/ApiClient/IApiClient.cs b/MediaBrowser.Model/ApiClient/IApiClient.cs
index 1e54e2dae5..d4d2a81240 100644
--- a/MediaBrowser.Model/ApiClient/IApiClient.cs
+++ b/MediaBrowser.Model/ApiClient/IApiClient.cs
@@ -818,15 +818,6 @@ namespace MediaBrowser.Model.ApiClient
/// name
string GetPersonImageUrl(string name, ImageOptions options);
- ///
- /// Gets the year image URL.
- ///
- /// The item.
- /// The options.
- /// System.String.
- /// item
- string GetYearImageUrl(BaseItemDto item, ImageOptions options);
-
///
/// Gets an image url that can be used to download an image from the api
///
diff --git a/MediaBrowser.Providers/Manager/ItemImageProvider.cs b/MediaBrowser.Providers/Manager/ItemImageProvider.cs
index 773ad354c6..7610f72490 100644
--- a/MediaBrowser.Providers/Manager/ItemImageProvider.cs
+++ b/MediaBrowser.Providers/Manager/ItemImageProvider.cs
@@ -119,13 +119,13 @@ namespace MediaBrowser.Providers.Manager
var stream = _fileSystem.GetFileStream(response.Path, FileMode.Open, FileAccess.Read, FileShare.Read, true);
- await _providerManager.SaveImage((BaseItem)item, stream, mimeType, imageType, null, cancellationToken).ConfigureAwait(false);
+ await _providerManager.SaveImage(item, stream, mimeType, imageType, null, cancellationToken).ConfigureAwait(false);
}
else
{
var mimeType = "image/" + response.Format.ToString().ToLower();
- await _providerManager.SaveImage((BaseItem)item, response.Stream, mimeType, imageType, null, cancellationToken).ConfigureAwait(false);
+ await _providerManager.SaveImage(item, response.Stream, mimeType, imageType, null, cancellationToken).ConfigureAwait(false);
}
result.UpdateType = result.UpdateType | ItemUpdateType.ImageUpdate;
@@ -325,7 +325,7 @@ namespace MediaBrowser.Providers.Manager
{
var response = await provider.GetImageResponse(url, cancellationToken).ConfigureAwait(false);
- await _providerManager.SaveImage((BaseItem)item, response.Content, response.ContentType, type, null, cancellationToken).ConfigureAwait(false);
+ await _providerManager.SaveImage(item, response.Content, response.ContentType, type, null, cancellationToken).ConfigureAwait(false);
result.UpdateType = result.UpdateType | ItemUpdateType.ImageUpdate;
break;
@@ -362,7 +362,7 @@ namespace MediaBrowser.Providers.Manager
{
var response = await provider.GetImageResponse(url, cancellationToken).ConfigureAwait(false);
- await _providerManager.SaveImage((BaseItem)item, response.Content, response.ContentType, imageType, null, cancellationToken).ConfigureAwait(false);
+ await _providerManager.SaveImage(item, response.Content, response.ContentType, imageType, null, cancellationToken).ConfigureAwait(false);
result.UpdateType = result.UpdateType | ItemUpdateType.ImageUpdate;
break;
}
diff --git a/MediaBrowser.Providers/MediaInfo/FFProbeAudioInfo.cs b/MediaBrowser.Providers/MediaInfo/FFProbeAudioInfo.cs
index e79fa65fb5..044973064e 100644
--- a/MediaBrowser.Providers/MediaInfo/FFProbeAudioInfo.cs
+++ b/MediaBrowser.Providers/MediaInfo/FFProbeAudioInfo.cs
@@ -183,7 +183,10 @@ namespace MediaBrowser.Providers.MediaInfo
audio.ProductionYear = FFProbeHelpers.GetDictionaryNumericValue(tags, "date");
// Several different forms of retaildate
- audio.PremiereDate = FFProbeHelpers.GetDictionaryDateTime(tags, "retaildate") ?? FFProbeHelpers.GetDictionaryDateTime(tags, "retail date") ?? FFProbeHelpers.GetDictionaryDateTime(tags, "retail_date");
+ audio.PremiereDate = FFProbeHelpers.GetDictionaryDateTime(tags, "retaildate") ??
+ FFProbeHelpers.GetDictionaryDateTime(tags, "retail date") ??
+ FFProbeHelpers.GetDictionaryDateTime(tags, "retail_date") ??
+ FFProbeHelpers.GetDictionaryDateTime(tags, "date");
// If we don't have a ProductionYear try and get it from PremiereDate
if (audio.PremiereDate.HasValue && !audio.ProductionYear.HasValue)
diff --git a/MediaBrowser.Providers/MediaInfo/FFProbeVideoInfo.cs b/MediaBrowser.Providers/MediaInfo/FFProbeVideoInfo.cs
index f55fc4cf56..551b417cb4 100644
--- a/MediaBrowser.Providers/MediaInfo/FFProbeVideoInfo.cs
+++ b/MediaBrowser.Providers/MediaInfo/FFProbeVideoInfo.cs
@@ -516,8 +516,6 @@ namespace MediaBrowser.Providers.MediaInfo
var path = mount == null ? item.Path : mount.MountedPath;
var dvd = new Dvd(path);
- item.RunTimeTicks = dvd.Titles.Select(GetRuntime).Max();
-
var primaryTitle = dvd.Titles.OrderByDescending(GetRuntime).FirstOrDefault();
uint? titleNumber = null;
@@ -525,6 +523,7 @@ namespace MediaBrowser.Providers.MediaInfo
if (primaryTitle != null)
{
titleNumber = primaryTitle.TitleNumber;
+ item.RunTimeTicks = GetRuntime(primaryTitle);
}
item.PlayableStreamFileNames = GetPrimaryPlaylistVobFiles(item, mount, titleNumber)
diff --git a/MediaBrowser.Server.Implementations/Library/LibraryManager.cs b/MediaBrowser.Server.Implementations/Library/LibraryManager.cs
index 5bc1ff45a6..b59e95c727 100644
--- a/MediaBrowser.Server.Implementations/Library/LibraryManager.cs
+++ b/MediaBrowser.Server.Implementations/Library/LibraryManager.cs
@@ -279,7 +279,7 @@ namespace MediaBrowser.Server.Implementations.Library
if (ibnPathChanged)
{
- _itemsByName.Clear();
+ RemoveItemsByNameFromCache();
}
var newSeasonZeroName = ConfigurationManager.Configuration.SeasonZeroDisplayName;
@@ -302,6 +302,32 @@ namespace MediaBrowser.Server.Implementations.Library
});
}
+ private void RemoveItemsByNameFromCache()
+ {
+ RemoveItemsFromCache(i => i is Person);
+ RemoveItemsFromCache(i => i is Year);
+ RemoveItemsFromCache(i => i is Genre);
+ RemoveItemsFromCache(i => i is MusicGenre);
+ RemoveItemsFromCache(i => i is GameGenre);
+ RemoveItemsFromCache(i => i is Studio);
+ RemoveItemsFromCache(i =>
+ {
+ var artist = i as MusicArtist;
+ return artist != null && artist.IsAccessedByName;
+ });
+ }
+
+ private void RemoveItemsFromCache(Func remove)
+ {
+ var items = _libraryItemsCache.ToList().Where(i => remove(i.Value)).ToList();
+
+ foreach (var item in items)
+ {
+ BaseItem value;
+ _libraryItemsCache.TryRemove(item.Key, out value);
+ }
+ }
+
///
/// Updates the season zero names.
///
@@ -378,28 +404,17 @@ namespace MediaBrowser.Server.Implementations.Library
/// The item.
private void UpdateItemInLibraryCache(BaseItem item)
{
- if (item is IItemByName)
- {
- var hasDualAccess = item as IHasDualAccess;
- if (hasDualAccess != null)
- {
- if (hasDualAccess.IsAccessedByName)
- {
- return;
- }
- }
- else
- {
- return;
- }
- }
-
RegisterItem(item);
}
public void RegisterItem(BaseItem item)
{
- LibraryItemsCache.AddOrUpdate(item.Id, item, delegate { return item; });
+ RegisterItem(item.Id, item);
+ }
+
+ private void RegisterItem(Guid id, BaseItem item)
+ {
+ LibraryItemsCache.AddOrUpdate(id, item, delegate { return item; });
}
public async Task DeleteItem(BaseItem item, DeleteOptions options)
@@ -580,7 +595,7 @@ namespace MediaBrowser.Server.Implementations.Library
var flattenFolderDepth = isPhysicalRoot ? 2 : 0;
var fileSystemDictionary = FileData.GetFilteredFileSystemEntries(directoryService, args.Path, _fileSystem, _logger, args, flattenFolderDepth: flattenFolderDepth, resolveShortcuts: isPhysicalRoot || args.IsVf);
-
+
// Need to remove subpaths that may have been resolved from shortcuts
// Example: if \\server\movies exists, then strip out \\server\movies\action
if (isPhysicalRoot)
@@ -790,11 +805,6 @@ namespace MediaBrowser.Server.Implementations.Library
return GetItemByName(ConfigurationManager.ApplicationPaths.ArtistsPath, name);
}
- ///
- /// The images by name item cache
- ///
- private readonly ConcurrentDictionary _itemsByName = new ConcurrentDictionary(StringComparer.OrdinalIgnoreCase);
-
private T GetItemByName(string path, string name)
where T : BaseItem, new()
{
@@ -812,24 +822,26 @@ namespace MediaBrowser.Server.Implementations.Library
string subFolderPrefix = null;
- if (typeof(T) == typeof(Person) && ConfigurationManager.Configuration.EnablePeoplePrefixSubFolders)
+ var type = typeof(T);
+
+ if (type == typeof(Person) && ConfigurationManager.Configuration.EnablePeoplePrefixSubFolders)
{
subFolderPrefix = validFilename.Substring(0, 1);
}
- var key = string.IsNullOrEmpty(subFolderPrefix) ?
+ var fullPath = string.IsNullOrEmpty(subFolderPrefix) ?
Path.Combine(path, validFilename) :
Path.Combine(path, subFolderPrefix, validFilename);
+ var id = fullPath.GetMBId(type);
+
BaseItem obj;
- if (!_itemsByName.TryGetValue(key, out obj))
+ if (!_libraryItemsCache.TryGetValue(id, out obj))
{
- var tuple = CreateItemByName(key, name);
+ obj = CreateItemByName(fullPath, name, id);
- obj = tuple.Item2;
-
- _itemsByName.AddOrUpdate(key, obj, (keyName, oldValue) => obj);
+ RegisterItem(id, obj);
}
return obj as T;
@@ -843,7 +855,7 @@ namespace MediaBrowser.Server.Implementations.Library
/// The name.
/// Task{``0}.
/// Path not created: + path
- private Tuple CreateItemByName(string path, string name)
+ private T CreateItemByName(string path, string name, Guid id)
where T : BaseItem, new()
{
var isArtist = typeof(T) == typeof(MusicArtist);
@@ -856,7 +868,7 @@ namespace MediaBrowser.Server.Implementations.Library
if (existing != null)
{
- return new Tuple(false, existing);
+ return existing;
}
}
@@ -877,10 +889,6 @@ namespace MediaBrowser.Server.Implementations.Library
isNew = true;
}
- var type = typeof(T);
-
- var id = path.GetMBId(type);
-
var item = isNew ? null : RetrieveItem(id) as T;
if (item == null)
@@ -893,7 +901,6 @@ namespace MediaBrowser.Server.Implementations.Library
DateModified = _fileSystem.GetLastWriteTimeUtc(fileInfo),
Path = path
};
- isNew = true;
}
if (isArtist)
@@ -901,7 +908,7 @@ namespace MediaBrowser.Server.Implementations.Library
(item as MusicArtist).IsAccessedByName = true;
}
- return new Tuple(isNew, item);
+ return item;
}
///