diff --git a/MediaBrowser.Controller/Entities/BaseItem.cs b/MediaBrowser.Controller/Entities/BaseItem.cs
index 4f34f2b675..b7d2a75ec7 100644
--- a/MediaBrowser.Controller/Entities/BaseItem.cs
+++ b/MediaBrowser.Controller/Entities/BaseItem.cs
@@ -24,7 +24,11 @@ namespace MediaBrowser.Controller.Entities
///
public abstract class BaseItem : IHasProviderIds
{
- ///
+ private Guid _testId = Guid.NewGuid();
+ public Guid TestId
+ {
+ get { return _testId; }
+ } ///
/// The trailer folder name
///
public const string TrailerFolderName = "trailers";
diff --git a/MediaBrowser.Controller/Entities/BasePluginFolder.cs b/MediaBrowser.Controller/Entities/BasePluginFolder.cs
index 7cabcf9f01..ca6cfd246f 100644
--- a/MediaBrowser.Controller/Entities/BasePluginFolder.cs
+++ b/MediaBrowser.Controller/Entities/BasePluginFolder.cs
@@ -1,5 +1,6 @@
using MediaBrowser.Common.Extensions;
using System;
+using MediaBrowser.Model.Entities;
namespace MediaBrowser.Controller.Entities
{
@@ -7,7 +8,7 @@ namespace MediaBrowser.Controller.Entities
/// Plugins derive from and export this class to create a folder that will appear in the root along
/// with all the other actual physical folders in the system.
///
- public abstract class BasePluginFolder : Folder, ICollectionFolder
+ public abstract class BasePluginFolder : Folder, ICollectionFolder, IByReferenceItem
{
///
/// Gets or sets the id.
diff --git a/MediaBrowser.Controller/Entities/CollectionFolder.cs b/MediaBrowser.Controller/Entities/CollectionFolder.cs
index a3db5ca26a..091cbdc3b5 100644
--- a/MediaBrowser.Controller/Entities/CollectionFolder.cs
+++ b/MediaBrowser.Controller/Entities/CollectionFolder.cs
@@ -1,4 +1,5 @@
using MediaBrowser.Common.Extensions;
+using MediaBrowser.Model.Entities;
using MediaBrowser.Model.Tasks;
using System;
using System.Collections.Concurrent;
@@ -15,7 +16,7 @@ namespace MediaBrowser.Controller.Entities
/// Specialized Folder class that points to a subset of the physical folders in the system.
/// It is created from the user-specific folders within the system root
///
- public class CollectionFolder : Folder, ICollectionFolder
+ public class CollectionFolder : Folder, ICollectionFolder, IByReferenceItem
{
///
/// Gets a value indicating whether this instance is virtual folder.
diff --git a/MediaBrowser.Controller/Entities/Folder.cs b/MediaBrowser.Controller/Entities/Folder.cs
index ef34742df4..9e50969201 100644
--- a/MediaBrowser.Controller/Entities/Folder.cs
+++ b/MediaBrowser.Controller/Entities/Folder.cs
@@ -811,7 +811,7 @@ namespace MediaBrowser.Controller.Entities
/// IEnumerable{BaseItem}.
protected virtual IEnumerable GetCachedChildren()
{
- return Kernel.Instance.ItemRepository.RetrieveChildren(this);
+ return Kernel.Instance.ItemRepository.RetrieveChildren(this).Select(i => i is IByReferenceItem ? LibraryManager.GetOrAddByReferenceItem(i) : i);
}
///
diff --git a/MediaBrowser.Controller/Library/ILibraryManager.cs b/MediaBrowser.Controller/Library/ILibraryManager.cs
index dd720d043f..a69e064604 100644
--- a/MediaBrowser.Controller/Library/ILibraryManager.cs
+++ b/MediaBrowser.Controller/Library/ILibraryManager.cs
@@ -181,5 +181,12 @@ namespace MediaBrowser.Controller.Library
/// The search term.
/// IEnumerable{BaseItem}.
IEnumerable Search(IEnumerable items, string searchTerm);
+
+ ///
+ /// Ensure supplied item has only one instance throughout
+ ///
+ ///
+ /// The proper instance to the item
+ BaseItem GetOrAddByReferenceItem(BaseItem item);
}
}
\ No newline at end of file
diff --git a/MediaBrowser.Model/Entities/IByReferenceItem.cs b/MediaBrowser.Model/Entities/IByReferenceItem.cs
new file mode 100644
index 0000000000..7554ad36de
--- /dev/null
+++ b/MediaBrowser.Model/Entities/IByReferenceItem.cs
@@ -0,0 +1,16 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+
+namespace MediaBrowser.Model.Entities
+{
+ ///
+ /// This is a marker class that tells us that a particular item type may be physically resolved
+ /// more than once within the library and we need to be sure to resolve them all to the same
+ /// instance of that item.
+ ///
+ public interface IByReferenceItem
+ {
+ }
+}
diff --git a/MediaBrowser.Model/MediaBrowser.Model.csproj b/MediaBrowser.Model/MediaBrowser.Model.csproj
index 36f585e5cd..5f76c49cac 100644
--- a/MediaBrowser.Model/MediaBrowser.Model.csproj
+++ b/MediaBrowser.Model/MediaBrowser.Model.csproj
@@ -45,6 +45,7 @@
+
diff --git a/MediaBrowser.Server.Implementations/Library/LibraryManager.cs b/MediaBrowser.Server.Implementations/Library/LibraryManager.cs
index 549ea9be2a..71fe6e125b 100644
--- a/MediaBrowser.Server.Implementations/Library/LibraryManager.cs
+++ b/MediaBrowser.Server.Implementations/Library/LibraryManager.cs
@@ -105,6 +105,13 @@ namespace MediaBrowser.Server.Implementations.Library
/// The configuration manager.
private IServerConfigurationManager ConfigurationManager { get; set; }
+ ///
+ /// A collection of items that may be referenced from multiple physical places in the library
+ /// (typically, multiple user roots). We store them here and be sure they all reference a
+ /// single instance.
+ ///
+ private ConcurrentDictionary ByReferenceItems { get; set; }
+
///
/// Initializes a new instance of the class.
///
@@ -120,6 +127,7 @@ namespace MediaBrowser.Server.Implementations.Library
_taskManager = taskManager;
_userManager = userManager;
ConfigurationManager = configurationManager;
+ ByReferenceItems = new ConcurrentDictionary();
ConfigurationManager.ConfigurationUpdated += kernel_ConfigurationUpdated;
@@ -232,11 +240,35 @@ namespace MediaBrowser.Server.Implementations.Library
if (item != null)
{
ResolverHelper.SetInitialItemValues(item, args);
+
+ // Now handle the issue with posibly having the same item referenced from multiple physical
+ // places within the library. Be sure we always end up with just one instance.
+ if (item is IByReferenceItem)
+ {
+ item = GetOrAddByReferenceItem(item);
+ }
}
return item;
}
+
+ ///
+ /// Ensure supplied item has only one instance throughout
+ ///
+ ///
+ /// The proper instance to the item
+ public BaseItem GetOrAddByReferenceItem(BaseItem item)
+ {
+ // Add this item to our list if not there already
+ if (!ByReferenceItems.TryAdd(item.Id, item))
+ {
+ // Already there - return the existing reference
+ item = ByReferenceItems[item.Id];
+ }
+ return item;
+ }
+
///
/// Resolves a path into a BaseItem
///
@@ -617,10 +649,10 @@ namespace MediaBrowser.Server.Implementations.Library
// Now validate the entire media library
await RootFolder.ValidateChildren(progress, cancellationToken, recursive: true).ConfigureAwait(false);
- foreach (var user in _userManager.Users)
- {
- await user.ValidateMediaLibrary(new Progress { }, cancellationToken).ConfigureAwait(false);
- }
+ //foreach (var user in _userManager.Users)
+ //{
+ // await user.ValidateMediaLibrary(new Progress { }, cancellationToken).ConfigureAwait(false);
+ //}
}
///