aboutsummaryrefslogtreecommitdiff
path: root/Emby.Server.Implementations/Library/LibraryManager.cs
diff options
context:
space:
mode:
authorstefan <stefan@hegedues.at>2018-09-12 19:26:21 +0200
committerstefan <stefan@hegedues.at>2018-09-12 19:26:21 +0200
commit48facb797ed912e4ea6b04b17d1ff190ac2daac4 (patch)
tree8dae77a31670a888d733484cb17dd4077d5444e8 /Emby.Server.Implementations/Library/LibraryManager.cs
parentc32d8656382a0eacb301692e0084377fc433ae9b (diff)
Update to 3.5.2 and .net core 2.1
Diffstat (limited to 'Emby.Server.Implementations/Library/LibraryManager.cs')
-rw-r--r--Emby.Server.Implementations/Library/LibraryManager.cs700
1 files changed, 345 insertions, 355 deletions
diff --git a/Emby.Server.Implementations/Library/LibraryManager.cs b/Emby.Server.Implementations/Library/LibraryManager.cs
index 2934a5147..31af9370c 100644
--- a/Emby.Server.Implementations/Library/LibraryManager.cs
+++ b/Emby.Server.Implementations/Library/LibraryManager.cs
@@ -44,6 +44,9 @@ using MediaBrowser.Common.Configuration;
using MediaBrowser.Controller.Dto;
using MediaBrowser.Controller.LiveTv;
using MediaBrowser.Model.Tasks;
+using Emby.Server.Implementations.Playlists;
+using MediaBrowser.Providers.MediaInfo;
+using MediaBrowser.Controller;
namespace Emby.Server.Implementations.Library
{
@@ -71,12 +74,6 @@ namespace Emby.Server.Implementations.Library
private IResolverIgnoreRule[] EntityResolutionIgnoreRules { get; set; }
/// <summary>
- /// Gets the list of BasePluginFolders added by plugins
- /// </summary>
- /// <value>The plugin folders.</value>
- private IVirtualFolderCreator[] PluginFolderCreators { get; set; }
-
- /// <summary>
/// Gets the list of currently registered entity resolvers
/// </summary>
/// <value>The entity resolvers enumerable.</value>
@@ -140,6 +137,7 @@ namespace Emby.Server.Implementations.Library
private readonly Func<IProviderManager> _providerManagerFactory;
private readonly Func<IUserViewManager> _userviewManager;
public bool IsScanRunning { get; private set; }
+ private IServerApplicationHost _appHost;
/// <summary>
/// The _library items cache
@@ -167,7 +165,7 @@ namespace Emby.Server.Implementations.Library
/// <param name="userManager">The user manager.</param>
/// <param name="configurationManager">The configuration manager.</param>
/// <param name="userDataRepository">The user data repository.</param>
- public LibraryManager(ILogger logger, ITaskManager taskManager, IUserManager userManager, IServerConfigurationManager configurationManager, IUserDataManager userDataRepository, Func<ILibraryMonitor> libraryMonitorFactory, IFileSystem fileSystem, Func<IProviderManager> providerManagerFactory, Func<IUserViewManager> userviewManager)
+ public LibraryManager(IServerApplicationHost appHost, ILogger logger, ITaskManager taskManager, IUserManager userManager, IServerConfigurationManager configurationManager, IUserDataManager userDataRepository, Func<ILibraryMonitor> libraryMonitorFactory, IFileSystem fileSystem, Func<IProviderManager> providerManagerFactory, Func<IUserViewManager> userviewManager)
{
_logger = logger;
_taskManager = taskManager;
@@ -178,6 +176,7 @@ namespace Emby.Server.Implementations.Library
_fileSystem = fileSystem;
_providerManagerFactory = providerManagerFactory;
_userviewManager = userviewManager;
+ _appHost = appHost;
_libraryItemsCache = new ConcurrentDictionary<Guid, BaseItem>();
ConfigurationManager.ConfigurationUpdated += ConfigurationUpdated;
@@ -195,14 +194,12 @@ namespace Emby.Server.Implementations.Library
/// <param name="itemComparers">The item comparers.</param>
/// <param name="postscanTasks">The postscan tasks.</param>
public void AddParts(IEnumerable<IResolverIgnoreRule> rules,
- IEnumerable<IVirtualFolderCreator> pluginFolders,
IEnumerable<IItemResolver> resolvers,
IEnumerable<IIntroProvider> introProviders,
IEnumerable<IBaseItemComparer> itemComparers,
IEnumerable<ILibraryPostScanTask> postscanTasks)
{
EntityResolutionIgnoreRules = rules.ToArray();
- PluginFolderCreators = pluginFolders.ToArray();
EntityResolvers = resolvers.OrderBy(i => i.Priority).ToArray();
MultiItemResolvers = EntityResolvers.OfType<IMultiItemResolver>().ToArray();
IntroProviders = introProviders.ToArray();
@@ -302,7 +299,7 @@ namespace Emby.Server.Implementations.Library
}
else
{
- if (!(item is Video))
+ if (!(item is Video) && !(item is LiveTvChannel))
{
return;
}
@@ -311,13 +308,47 @@ namespace Emby.Server.Implementations.Library
LibraryItemsCache.AddOrUpdate(item.Id, item, delegate { return item; });
}
- public async Task DeleteItem(BaseItem item, DeleteOptions options)
+ public void DeleteItem(BaseItem item, DeleteOptions options)
+ {
+ DeleteItem(item, options, false);
+ }
+
+ public void DeleteItem(BaseItem item, DeleteOptions options, bool notifyParentItem)
+ {
+ if (item == null)
+ {
+ throw new ArgumentNullException("item");
+ }
+
+ var parent = item.GetOwner() ?? item.GetParent();
+
+ DeleteItem(item, options, parent, notifyParentItem);
+ }
+
+ public void DeleteItem(BaseItem item, DeleteOptions options, BaseItem parent, bool notifyParentItem)
{
if (item == null)
{
throw new ArgumentNullException("item");
}
+ if (item.SourceType == SourceType.Channel)
+ {
+ if (options.DeleteFromExternalProvider)
+ {
+ try
+ {
+ var task = BaseItem.ChannelManager.DeleteItem(item);
+ Task.WaitAll(task);
+ }
+ catch (ArgumentException)
+ {
+ // channel no longer installed
+ }
+ }
+ options.DeleteFileLocation = false;
+ }
+
if (item is LiveTvProgram)
{
_logger.Debug("Deleting item, Type: {0}, Name: {1}, Path: {2}, Id: {3}",
@@ -335,10 +366,6 @@ namespace Emby.Server.Implementations.Library
item.Id);
}
- var parent = item.IsOwnedItem ? item.GetOwner() : item.GetParent();
-
- var locationType = item.LocationType;
-
var children = item.IsFolder
? ((Folder)item).GetRecursiveChildren(false).ToList()
: new List<BaseItem>();
@@ -361,7 +388,7 @@ namespace Emby.Server.Implementations.Library
}
}
- if (options.DeleteFileLocation && locationType != LocationType.Remote && locationType != LocationType.Virtual)
+ if (options.DeleteFileLocation && item.IsFileProtocol)
{
// Assume only the first is required
// Add this flag to GetDeletePaths if required in the future
@@ -407,33 +434,10 @@ namespace Emby.Server.Implementations.Library
isRequiredForDelete = false;
}
-
- if (parent != null)
- {
- var parentFolder = parent as Folder;
- if (parentFolder != null)
- {
- await parentFolder.ValidateChildren(new SimpleProgress<double>(), CancellationToken.None, new MetadataRefreshOptions(_fileSystem), false).ConfigureAwait(false);
- }
- else
- {
- await parent.RefreshMetadata(new MetadataRefreshOptions(_fileSystem), CancellationToken.None).ConfigureAwait(false);
- }
- }
- }
- else if (parent != null)
- {
- var parentFolder = parent as Folder;
- if (parentFolder != null)
- {
- parentFolder.RemoveChild(item);
- }
- else
- {
- await parent.RefreshMetadata(new MetadataRefreshOptions(_fileSystem), CancellationToken.None).ConfigureAwait(false);
- }
}
+ item.SetParent(null);
+
ItemRepository.DeleteItem(item.Id, CancellationToken.None);
foreach (var child in children)
{
@@ -497,7 +501,7 @@ namespace Emby.Server.Implementations.Library
private Guid GetNewItemIdInternal(string key, Type type, bool forceCaseInsensitive)
{
- if (string.IsNullOrWhiteSpace(key))
+ if (string.IsNullOrEmpty(key))
{
throw new ArgumentNullException("key");
}
@@ -544,7 +548,7 @@ namespace Emby.Server.Implementations.Library
var fullPath = fileInfo.FullName;
- if (string.IsNullOrWhiteSpace(collectionType) && parent != null)
+ if (string.IsNullOrEmpty(collectionType) && parent != null)
{
collectionType = GetContentTypeOverride(fullPath, true);
}
@@ -572,7 +576,26 @@ namespace Emby.Server.Implementations.Library
// When resolving the root, we need it's grandchildren (children of user views)
var flattenFolderDepth = isPhysicalRoot ? 2 : 0;
- var files = FileData.GetFilteredFileSystemEntries(directoryService, args.Path, _fileSystem, _logger, args, flattenFolderDepth: flattenFolderDepth, resolveShortcuts: isPhysicalRoot || args.IsVf);
+ FileSystemMetadata[] files;
+ var isVf = args.IsVf;
+
+ try
+ {
+ files = FileData.GetFilteredFileSystemEntries(directoryService, args.Path, _fileSystem, _appHost, _logger, args, flattenFolderDepth: flattenFolderDepth, resolveShortcuts: isPhysicalRoot || isVf);
+ }
+ catch (Exception ex)
+ {
+ if (parent != null && parent.IsPhysicalRoot)
+ {
+ _logger.ErrorException("Error in GetFilteredFileSystemEntries isPhysicalRoot: {0} IsVf: {1}", ex, isPhysicalRoot, isVf);
+
+ files = new FileSystemMetadata[] { };
+ }
+ else
+ {
+ throw;
+ }
+ }
// Need to remove subpaths that may have been resolved from shortcuts
// Example: if \\server\movies exists, then strip out \\server\movies\action
@@ -717,42 +740,43 @@ namespace Emby.Server.Implementations.Library
}
// Add in the plug-in folders
- foreach (var child in PluginFolderCreators)
+ var path = Path.Combine(ConfigurationManager.ApplicationPaths.DataPath, "playlists");
+
+ _fileSystem.CreateDirectory(path);
+
+ Folder folder = new PlaylistsFolder
{
- var folder = child.GetFolder();
+ Path = path
+ };
- if (folder != null)
+ if (folder.Id.Equals(Guid.Empty))
+ {
+ if (string.IsNullOrEmpty(folder.Path))
{
- if (folder.Id == Guid.Empty)
- {
- if (string.IsNullOrWhiteSpace(folder.Path))
- {
- folder.Id = GetNewItemId(folder.GetType().Name, folder.GetType());
- }
- else
- {
- folder.Id = GetNewItemId(folder.Path, folder.GetType());
- }
- }
+ folder.Id = GetNewItemId(folder.GetType().Name, folder.GetType());
+ }
+ else
+ {
+ folder.Id = GetNewItemId(folder.Path, folder.GetType());
+ }
+ }
- var dbItem = GetItemById(folder.Id) as BasePluginFolder;
+ var dbItem = GetItemById(folder.Id) as BasePluginFolder;
- if (dbItem != null && string.Equals(dbItem.Path, folder.Path, StringComparison.OrdinalIgnoreCase))
- {
- folder = dbItem;
- }
+ if (dbItem != null && string.Equals(dbItem.Path, folder.Path, StringComparison.OrdinalIgnoreCase))
+ {
+ folder = dbItem;
+ }
- if (folder.ParentId != rootFolder.Id)
- {
- folder.ParentId = rootFolder.Id;
- folder.UpdateToRepository(ItemUpdateType.MetadataImport, CancellationToken.None);
- }
+ if (folder.ParentId != rootFolder.Id)
+ {
+ folder.ParentId = rootFolder.Id;
+ folder.UpdateToRepository(ItemUpdateType.MetadataImport, CancellationToken.None);
+ }
- rootFolder.AddVirtualChild(folder);
+ rootFolder.AddVirtualChild(folder);
- RegisterItem(folder);
- }
- }
+ RegisterItem(folder);
return rootFolder;
}
@@ -798,16 +822,18 @@ namespace Emby.Server.Implementations.Library
// If this returns multiple items it could be tricky figuring out which one is correct.
// In most cases, the newest one will be and the others obsolete but not yet cleaned up
- if (string.IsNullOrWhiteSpace(path))
+ if (string.IsNullOrEmpty(path))
{
throw new ArgumentNullException("path");
}
+ //_logger.Info("FindByPath {0}", path);
+
var query = new InternalItemsQuery
{
Path = path,
IsFolder = isFolder,
- OrderBy = new[] { ItemSortBy.DateCreated }.Select(i => new Tuple<string, SortOrder>(i, SortOrder.Descending)).ToArray(),
+ OrderBy = new[] { ItemSortBy.DateCreated }.Select(i => new ValueTuple<string, SortOrder>(i, SortOrder.Descending)).ToArray(),
Limit = 1,
DtoOptions = new DtoOptions(true)
};
@@ -957,7 +983,7 @@ namespace Emby.Server.Implementations.Library
Path = path
};
- CreateItem(item, CancellationToken.None);
+ CreateItem(item, null);
}
return item;
@@ -997,7 +1023,7 @@ namespace Emby.Server.Implementations.Library
// Just run the scheduled task so that the user can see it
_taskManager.CancelIfRunningAndQueue<RefreshMediaLibraryTask>();
- return Task.FromResult(true);
+ return Task.CompletedTask;
}
/// <summary>
@@ -1031,48 +1057,45 @@ namespace Emby.Server.Implementations.Library
}
}
- private async Task PerformLibraryValidation(IProgress<double> progress, CancellationToken cancellationToken)
+ private async Task ValidateTopLibraryFolders(CancellationToken cancellationToken)
{
- _logger.Info("Validating media library");
-
- // Ensure these objects are lazy loaded.
- // Without this there is a deadlock that will need to be investigated
var rootChildren = RootFolder.Children.ToList();
rootChildren = GetUserRootFolder().Children.ToList();
await RootFolder.RefreshMetadata(cancellationToken).ConfigureAwait(false);
- progress.Report(.5);
-
// Start by just validating the children of the root, but go no further
await RootFolder.ValidateChildren(new SimpleProgress<double>(), cancellationToken, new MetadataRefreshOptions(_fileSystem), recursive: false);
- progress.Report(1);
-
await GetUserRootFolder().RefreshMetadata(cancellationToken).ConfigureAwait(false);
await GetUserRootFolder().ValidateChildren(new SimpleProgress<double>(), cancellationToken, new MetadataRefreshOptions(_fileSystem), recursive: false).ConfigureAwait(false);
- progress.Report(2);
// Quickly scan CollectionFolders for changes
foreach (var folder in GetUserRootFolder().Children.OfType<Folder>().ToList())
{
await folder.RefreshMetadata(cancellationToken).ConfigureAwait(false);
}
- progress.Report(3);
+ }
+
+ private async Task PerformLibraryValidation(IProgress<double> progress, CancellationToken cancellationToken)
+ {
+ _logger.Info("Validating media library");
+
+ await ValidateTopLibraryFolders(cancellationToken).ConfigureAwait(false);
var innerProgress = new ActionableProgress<double>();
- innerProgress.RegisterAction(pct => progress.Report(3 + pct * .72));
+ innerProgress.RegisterAction(pct => progress.Report(pct * .96));
// Now validate the entire media library
await RootFolder.ValidateChildren(innerProgress, cancellationToken, new MetadataRefreshOptions(_fileSystem), recursive: true).ConfigureAwait(false);
- progress.Report(75);
+ progress.Report(96);
innerProgress = new ActionableProgress<double>();
- innerProgress.RegisterAction(pct => progress.Report(75 + pct * .25));
+ innerProgress.RegisterAction(pct => progress.Report(96 + (pct * .04)));
// Run post-scan tasks
await RunPostScanTasks(innerProgress, cancellationToken).ConfigureAwait(false);
@@ -1102,8 +1125,13 @@ namespace Emby.Server.Implementations.Library
innerProgress.RegisterAction(pct =>
{
- double innerPercent = currentNumComplete * 100 + pct;
+ double innerPercent = pct;
+ innerPercent /= 100;
+ innerPercent += currentNumComplete;
+
innerPercent /= numTasks;
+ innerPercent *= 100;
+
progress.Report(innerPercent);
});
@@ -1163,7 +1191,19 @@ namespace Emby.Server.Implementations.Library
Locations = _fileSystem.GetFilePaths(dir, false)
.Where(i => string.Equals(ShortcutFileExtension, Path.GetExtension(i), StringComparison.OrdinalIgnoreCase))
- .Select(_fileSystem.ResolveShortcut)
+ .Select(i =>
+ {
+ try
+ {
+ return _appHost.ExpandVirtualPath(_fileSystem.ResolveShortcut(i));
+ }
+ catch (Exception ex)
+ {
+ _logger.ErrorException("Error resolving shortcut file {0}", ex, i);
+ return null;
+ }
+ })
+ .Where(i => i != null)
.OrderBy(i => i)
.ToArray(),
@@ -1197,7 +1237,7 @@ namespace Emby.Server.Implementations.Library
{
return _fileSystem.GetFilePaths(path, new[] { ".collection" }, true, false)
.Select(i => _fileSystem.GetFileNameWithoutExtension(i))
- .FirstOrDefault(i => !string.IsNullOrWhiteSpace(i));
+ .FirstOrDefault(i => !string.IsNullOrEmpty(i));
}
/// <summary>
@@ -1208,7 +1248,7 @@ namespace Emby.Server.Implementations.Library
/// <exception cref="System.ArgumentNullException">id</exception>
public BaseItem GetItemById(Guid id)
{
- if (id == Guid.Empty)
+ if (id.Equals(Guid.Empty))
{
throw new ArgumentNullException("id");
}
@@ -1234,9 +1274,9 @@ namespace Emby.Server.Implementations.Library
public List<BaseItem> GetItemList(InternalItemsQuery query, bool allowExternalContent)
{
- if (query.Recursive && query.ParentId.HasValue)
+ if (query.Recursive && !query.ParentId.Equals(Guid.Empty))
{
- var parent = GetItemById(query.ParentId.Value);
+ var parent = GetItemById(query.ParentId);
if (parent != null)
{
SetTopParentIdsOrAncestors(query, new List<BaseItem> { parent });
@@ -1258,9 +1298,9 @@ namespace Emby.Server.Implementations.Library
public int GetCount(InternalItemsQuery query)
{
- if (query.Recursive && query.ParentId.HasValue)
+ if (query.Recursive && !query.ParentId.Equals(Guid.Empty))
{
- var parent = GetItemById(query.ParentId.Value);
+ var parent = GetItemById(query.ParentId);
if (parent != null)
{
SetTopParentIdsOrAncestors(query, new List<BaseItem> { parent });
@@ -1391,7 +1431,7 @@ namespace Emby.Server.Implementations.Library
return;
}
- var parents = query.AncestorIds.Select(i => GetItemById(new Guid(i))).ToList();
+ var parents = query.AncestorIds.Select(i => GetItemById(i)).ToList();
if (parents.All(i =>
{
@@ -1406,13 +1446,13 @@ namespace Emby.Server.Implementations.Library
}))
{
// Optimize by querying against top level views
- query.TopParentIds = parents.SelectMany(i => GetTopParentIdsForQuery(i, query.User)).Select(i => i.ToString("N")).ToArray();
- query.AncestorIds = new string[] { };
+ query.TopParentIds = parents.SelectMany(i => GetTopParentIdsForQuery(i, query.User)).ToArray();
+ query.AncestorIds = Array.Empty<Guid>();
// Prevent searching in all libraries due to empty filter
if (query.TopParentIds.Length == 0)
{
- query.TopParentIds = new[] { Guid.NewGuid().ToString("N") };
+ query.TopParentIds = new[] { Guid.NewGuid() };
}
}
}
@@ -1430,9 +1470,9 @@ namespace Emby.Server.Implementations.Library
public QueryResult<BaseItem> GetItemsResult(InternalItemsQuery query)
{
- if (query.Recursive && query.ParentId.HasValue)
+ if (query.Recursive && !query.ParentId.Equals(Guid.Empty))
{
- var parent = GetItemById(query.ParentId.Value);
+ var parent = GetItemById(query.ParentId);
if (parent != null)
{
SetTopParentIdsOrAncestors(query, new List<BaseItem> { parent });
@@ -1472,23 +1512,23 @@ namespace Emby.Server.Implementations.Library
}))
{
// Optimize by querying against top level views
- query.TopParentIds = parents.SelectMany(i => GetTopParentIdsForQuery(i, query.User)).Select(i => i.ToString("N")).ToArray();
+ query.TopParentIds = parents.SelectMany(i => GetTopParentIdsForQuery(i, query.User)).ToArray();
// Prevent searching in all libraries due to empty filter
if (query.TopParentIds.Length == 0)
{
- query.TopParentIds = new[] { Guid.NewGuid().ToString("N") };
+ query.TopParentIds = new[] { Guid.NewGuid() };
}
}
else
{
// We need to be able to query from any arbitrary ancestor up the tree
- query.AncestorIds = parents.SelectMany(i => i.GetIdsForAncestorQuery()).Select(i => i.ToString("N")).ToArray();
+ query.AncestorIds = parents.SelectMany(i => i.GetIdsForAncestorQuery()).ToArray();
// Prevent searching in all libraries due to empty filter
if (query.AncestorIds.Length == 0)
{
- query.AncestorIds = new[] { Guid.NewGuid().ToString("N") };
+ query.AncestorIds = new[] { Guid.NewGuid() };
}
}
@@ -1498,22 +1538,21 @@ namespace Emby.Server.Implementations.Library
private void AddUserToQuery(InternalItemsQuery query, User user, bool allowExternalContent = true)
{
if (query.AncestorIds.Length == 0 &&
- !query.ParentId.HasValue &&
+ query.ParentId.Equals(Guid.Empty) &&
query.ChannelIds.Length == 0 &&
query.TopParentIds.Length == 0 &&
- string.IsNullOrWhiteSpace(query.AncestorWithPresentationUniqueKey) &&
- string.IsNullOrWhiteSpace(query.SeriesPresentationUniqueKey) &&
+ string.IsNullOrEmpty(query.AncestorWithPresentationUniqueKey) &&
+ string.IsNullOrEmpty(query.SeriesPresentationUniqueKey) &&
query.ItemIds.Length == 0)
{
var userViews = _userviewManager().GetUserViews(new UserViewQuery
{
- UserId = user.Id.ToString("N"),
+ UserId = user.Id,
IncludeHidden = true,
IncludeExternalContent = allowExternalContent
+ });
- }, CancellationToken.None).Result;
-
- query.TopParentIds = userViews.SelectMany(i => GetTopParentIdsForQuery(i, user)).Select(i => i.ToString("N")).ToArray();
+ query.TopParentIds = userViews.SelectMany(i => GetTopParentIdsForQuery(i, user)).ToArray();
}
}
@@ -1527,48 +1566,38 @@ namespace Emby.Server.Implementations.Library
{
return new[] { view.Id };
}
- if (string.Equals(view.ViewType, CollectionType.Channels))
- {
- var channelResult = BaseItem.ChannelManager.GetChannelsInternal(new ChannelQuery
- {
- UserId = user.Id.ToString("N")
-
- }, CancellationToken.None).Result;
-
- return channelResult.Items.Select(i => i.Id);
- }
// Translate view into folders
- if (view.DisplayParentId != Guid.Empty)
+ if (!view.DisplayParentId.Equals(Guid.Empty))
{
var displayParent = GetItemById(view.DisplayParentId);
if (displayParent != null)
{
return GetTopParentIdsForQuery(displayParent, user);
}
- return new Guid[] { };
+ return Array.Empty<Guid>();
}
- if (view.ParentId != Guid.Empty)
+ if (!view.ParentId.Equals(Guid.Empty))
{
var displayParent = GetItemById(view.ParentId);
if (displayParent != null)
{
return GetTopParentIdsForQuery(displayParent, user);
}
- return new Guid[] { };
+ return Array.Empty<Guid>();
}
// Handle grouping
- if (user != null && !string.IsNullOrWhiteSpace(view.ViewType) && UserView.IsEligibleForGrouping(view.ViewType) && user.Configuration.GroupedFolders.Length > 0)
+ if (user != null && !string.IsNullOrEmpty(view.ViewType) && UserView.IsEligibleForGrouping(view.ViewType) && user.Configuration.GroupedFolders.Length > 0)
{
- return user.RootFolder
+ return GetUserRootFolder()
.GetChildren(user, true)
.OfType<CollectionFolder>()
- .Where(i => string.IsNullOrWhiteSpace(i.CollectionType) || string.Equals(i.CollectionType, view.ViewType, StringComparison.OrdinalIgnoreCase))
+ .Where(i => string.IsNullOrEmpty(i.CollectionType) || string.Equals(i.CollectionType, view.ViewType, StringComparison.OrdinalIgnoreCase))
.Where(i => user.IsFolderGrouped(i.Id))
.SelectMany(i => GetTopParentIdsForQuery(i, user));
}
- return new Guid[] { };
+ return Array.Empty<Guid>();
}
var collectionFolder = item as CollectionFolder;
@@ -1582,7 +1611,7 @@ namespace Emby.Server.Implementations.Library
{
return new[] { topParent.Id };
}
- return new Guid[] { };
+ return Array.Empty<Guid>();
}
/// <summary>
@@ -1737,7 +1766,7 @@ namespace Emby.Server.Implementations.Library
return orderedItems ?? items;
}
- public IEnumerable<BaseItem> Sort(IEnumerable<BaseItem> items, User user, IEnumerable<Tuple<string, SortOrder>> orderByList)
+ public IEnumerable<BaseItem> Sort(IEnumerable<BaseItem> items, User user, IEnumerable<ValueTuple<string, SortOrder>> orderByList)
{
var isFirst = true;
@@ -1802,9 +1831,9 @@ namespace Emby.Server.Implementations.Library
/// <param name="item">The item.</param>
/// <param name="cancellationToken">The cancellation token.</param>
/// <returns>Task.</returns>
- public void CreateItem(BaseItem item, CancellationToken cancellationToken)
+ public void CreateItem(BaseItem item, BaseItem parent)
{
- CreateItems(new[] { item }, item.GetParent(), cancellationToken);
+ CreateItems(new[] { item }, parent, CancellationToken.None);
}
/// <summary>
@@ -1828,6 +1857,12 @@ namespace Emby.Server.Implementations.Library
{
foreach (var item in list)
{
+ // With the live tv guide this just creates too much noise
+ if (item.SourceType != SourceType.Library)
+ {
+ continue;
+ }
+
try
{
ItemAdded(this, new ItemChangeEventArgs
@@ -1854,46 +1889,65 @@ namespace Emby.Server.Implementations.Library
/// <summary>
/// Updates the item.
/// </summary>
- /// <param name="item">The item.</param>
- /// <param name="updateReason">The update reason.</param>
- /// <param name="cancellationToken">The cancellation token.</param>
- /// <returns>Task.</returns>
- public void UpdateItem(BaseItem item, ItemUpdateType updateReason, CancellationToken cancellationToken)
+ public void UpdateItems(List<BaseItem> items, BaseItem parent, ItemUpdateType updateReason, CancellationToken cancellationToken)
{
- var locationType = item.LocationType;
- if (locationType != LocationType.Remote && locationType != LocationType.Virtual)
+ foreach (var item in items)
{
- _providerManagerFactory().SaveMetadata(item, updateReason);
- }
+ if (item.IsFileProtocol)
+ {
+ _providerManagerFactory().SaveMetadata(item, updateReason);
+ }
- item.DateLastSaved = DateTime.UtcNow;
+ item.DateLastSaved = DateTime.UtcNow;
- var logName = item.LocationType == LocationType.Remote ? item.Name ?? item.Path : item.Path ?? item.Name;
- _logger.Debug("Saving {0} to database.", logName);
+ RegisterItem(item);
+ }
- ItemRepository.SaveItem(item, cancellationToken);
+ //var logName = item.LocationType == LocationType.Remote ? item.Name ?? item.Path : item.Path ?? item.Name;
+ //_logger.Debug("Saving {0} to database.", logName);
- RegisterItem(item);
+ ItemRepository.SaveItems(items, cancellationToken);
if (ItemUpdated != null)
{
- try
+ foreach (var item in items)
{
- ItemUpdated(this, new ItemChangeEventArgs
+ // With the live tv guide this just creates too much noise
+ if (item.SourceType != SourceType.Library)
{
- Item = item,
- Parent = item.GetParent(),
- UpdateReason = updateReason
- });
- }
- catch (Exception ex)
- {
- _logger.ErrorException("Error in ItemUpdated event handler", ex);
+ continue;
+ }
+
+ try
+ {
+ ItemUpdated(this, new ItemChangeEventArgs
+ {
+ Item = item,
+ Parent = parent,
+ UpdateReason = updateReason
+ });
+ }
+ catch (Exception ex)
+ {
+ _logger.ErrorException("Error in ItemUpdated event handler", ex);
+ }
}
}
}
/// <summary>
+ /// Updates the item.
+ /// </summary>
+ /// <param name="item">The item.</param>
+ /// <param name="updateReason">The update reason.</param>
+ /// <param name="cancellationToken">The cancellation token.</param>
+ /// <returns>Task.</returns>
+ public void UpdateItem(BaseItem item, BaseItem parent, ItemUpdateType updateReason, CancellationToken cancellationToken)
+ {
+ UpdateItems(new List<BaseItem> { item }, parent, updateReason, cancellationToken);
+ }
+
+ /// <summary>
/// Reports the item removed.
/// </summary>
/// <param name="item">The item.</param>
@@ -1995,12 +2049,12 @@ namespace Emby.Server.Implementations.Library
public string GetContentType(BaseItem item)
{
string configuredContentType = GetConfiguredContentType(item, false);
- if (!string.IsNullOrWhiteSpace(configuredContentType))
+ if (!string.IsNullOrEmpty(configuredContentType))
{
return configuredContentType;
}
configuredContentType = GetConfiguredContentType(item, true);
- if (!string.IsNullOrWhiteSpace(configuredContentType))
+ if (!string.IsNullOrEmpty(configuredContentType))
{
return configuredContentType;
}
@@ -2011,14 +2065,14 @@ namespace Emby.Server.Implementations.Library
{
var type = GetTopFolderContentType(item);
- if (!string.IsNullOrWhiteSpace(type))
+ if (!string.IsNullOrEmpty(type))
{
return type;
}
return item.GetParents()
.Select(GetConfiguredContentType)
- .LastOrDefault(i => !string.IsNullOrWhiteSpace(i));
+ .LastOrDefault(i => !string.IsNullOrEmpty(i));
}
public string GetConfiguredContentType(BaseItem item)
@@ -2043,7 +2097,7 @@ namespace Emby.Server.Implementations.Library
private string GetContentTypeOverride(string path, bool inherit)
{
- var nameValuePair = ConfigurationManager.Configuration.ContentTypes.FirstOrDefault(i => _fileSystem.AreEqual(i.Name, path) || (inherit && !string.IsNullOrWhiteSpace(i.Name) && _fileSystem.ContainsSubPath(i.Name, path)));
+ var nameValuePair = ConfigurationManager.Configuration.ContentTypes.FirstOrDefault(i => _fileSystem.AreEqual(i.Name, path) || (inherit && !string.IsNullOrEmpty(i.Name) && _fileSystem.ContainsSubPath(i.Name, path)));
if (nameValuePair != null)
{
return nameValuePair.Value;
@@ -2058,16 +2112,21 @@ namespace Emby.Server.Implementations.Library
return null;
}
- while (!(item.GetParent() is AggregateFolder) && item.GetParent() != null)
+ while (!item.ParentId.Equals(Guid.Empty))
{
- item = item.GetParent();
+ var parent = item.GetParent();
+ if (parent == null || parent is AggregateFolder)
+ {
+ break;
+ }
+ item = parent;
}
return GetUserRootFolder().Children
.OfType<ICollectionFolder>()
.Where(i => string.Equals(i.Path, item.Path, StringComparison.OrdinalIgnoreCase) || i.PhysicalLocations.Contains(item.Path))
.Select(i => i.CollectionType)
- .FirstOrDefault(i => !string.IsNullOrWhiteSpace(i));
+ .FirstOrDefault(i => !string.IsNullOrEmpty(i));
}
private readonly TimeSpan _viewRefreshInterval = TimeSpan.FromHours(24);
@@ -2076,18 +2135,16 @@ namespace Emby.Server.Implementations.Library
public UserView GetNamedView(User user,
string name,
string viewType,
- string sortName,
- CancellationToken cancellationToken)
+ string sortName)
{
- return GetNamedView(user, name, null, viewType, sortName, cancellationToken);
+ return GetNamedView(user, name, Guid.Empty, viewType, sortName);
}
public UserView GetNamedView(string name,
string viewType,
- string sortName,
- CancellationToken cancellationToken)
+ string sortName)
{
- var path = Path.Combine(ConfigurationManager.ApplicationPaths.ItemsByNamePath, "views");
+ var path = Path.Combine(ConfigurationManager.ApplicationPaths.InternalMetadataPath, "views");
path = Path.Combine(path, _fileSystem.GetValidFilename(viewType));
@@ -2111,32 +2168,15 @@ namespace Emby.Server.Implementations.Library
ForcedSortName = sortName
};
- CreateItem(item, cancellationToken);
+ CreateItem(item, null);
refresh = true;
}
- if (!refresh)
- {
- refresh = DateTime.UtcNow - item.DateLastRefreshed >= _viewRefreshInterval;
- }
-
- if (!refresh && item.DisplayParentId != Guid.Empty)
- {
- var displayParent = GetItemById(item.DisplayParentId);
- refresh = displayParent != null && displayParent.DateLastSaved > item.DateLastRefreshed;
- }
-
if (refresh)
{
item.UpdateToRepository(ItemUpdateType.MetadataImport, CancellationToken.None);
- _providerManagerFactory().QueueRefresh(item.Id, new MetadataRefreshOptions(_fileSystem)
- {
- // Not sure why this is necessary but need to figure it out
- // View images are not getting utilized without this
- ForceSave = true
-
- }, RefreshPriority.Normal);
+ _providerManagerFactory().QueueRefresh(item.Id, new MetadataRefreshOptions(_fileSystem), RefreshPriority.Normal);
}
return item;
@@ -2144,12 +2184,12 @@ namespace Emby.Server.Implementations.Library
public UserView GetNamedView(User user,
string name,
- string parentId,
+ Guid parentId,
string viewType,
- string sortName,
- CancellationToken cancellationToken)
+ string sortName)
{
- var idValues = "38_namedview_" + name + user.Id.ToString("N") + (parentId ?? string.Empty) + (viewType ?? string.Empty);
+ var parentIdString = parentId.Equals(Guid.Empty) ? null : parentId.ToString("N");
+ var idValues = "38_namedview_" + name + user.Id.ToString("N") + (parentIdString ?? string.Empty) + (viewType ?? string.Empty);
var id = GetNewItemId(idValues, typeof(UserView));
@@ -2174,19 +2214,16 @@ namespace Emby.Server.Implementations.Library
UserId = user.Id
};
- if (!string.IsNullOrWhiteSpace(parentId))
- {
- item.DisplayParentId = new Guid(parentId);
- }
+ item.DisplayParentId = parentId;
- CreateItem(item, cancellationToken);
+ CreateItem(item, null);
isNew = true;
}
var refresh = isNew || DateTime.UtcNow - item.DateLastRefreshed >= _viewRefreshInterval;
- if (!refresh && item.DisplayParentId != Guid.Empty)
+ if (!refresh && !item.DisplayParentId.Equals(Guid.Empty))
{
var displayParent = GetItemById(item.DisplayParentId);
refresh = displayParent != null && displayParent.DateLastSaved > item.DateLastRefreshed;
@@ -2207,8 +2244,7 @@ namespace Emby.Server.Implementations.Library
public UserView GetShadowView(BaseItem parent,
string viewType,
- string sortName,
- CancellationToken cancellationToken)
+ string sortName)
{
if (parent == null)
{
@@ -2244,14 +2280,14 @@ namespace Emby.Server.Implementations.Library
item.DisplayParentId = parentId;
- CreateItem(item, cancellationToken);
+ CreateItem(item, null);
isNew = true;
}
var refresh = isNew || DateTime.UtcNow - item.DateLastRefreshed >= _viewRefreshInterval;
- if (!refresh && item.DisplayParentId != Guid.Empty)
+ if (!refresh && !item.DisplayParentId.Equals(Guid.Empty))
{
var displayParent = GetItemById(item.DisplayParentId);
refresh = displayParent != null && displayParent.DateLastSaved > item.DateLastRefreshed;
@@ -2271,19 +2307,19 @@ namespace Emby.Server.Implementations.Library
}
public UserView GetNamedView(string name,
- string parentId,
+ Guid parentId,
string viewType,
string sortName,
- string uniqueId,
- CancellationToken cancellationToken)
+ string uniqueId)
{
- if (string.IsNullOrWhiteSpace(name))
+ if (string.IsNullOrEmpty(name))
{
throw new ArgumentNullException("name");
}
- var idValues = "37_namedview_" + name + (parentId ?? string.Empty) + (viewType ?? string.Empty);
- if (!string.IsNullOrWhiteSpace(uniqueId))
+ var parentIdString = parentId.Equals(Guid.Empty) ? null : parentId.ToString("N");
+ var idValues = "37_namedview_" + name + (parentIdString ?? string.Empty) + (viewType ?? string.Empty);
+ if (!string.IsNullOrEmpty(uniqueId))
{
idValues += uniqueId;
}
@@ -2310,12 +2346,9 @@ namespace Emby.Server.Implementations.Library
ForcedSortName = sortName
};
- if (!string.IsNullOrWhiteSpace(parentId))
- {
- item.DisplayParentId = new Guid(parentId);
- }
+ item.DisplayParentId = parentId;
- CreateItem(item, cancellationToken);
+ CreateItem(item, null);
isNew = true;
}
@@ -2323,12 +2356,12 @@ namespace Emby.Server.Implementations.Library
if (!string.Equals(viewType, item.ViewType, StringComparison.OrdinalIgnoreCase))
{
item.ViewType = viewType;
- item.UpdateToRepository(ItemUpdateType.MetadataEdit, cancellationToken);
+ item.UpdateToRepository(ItemUpdateType.MetadataEdit, CancellationToken.None);
}
var refresh = isNew || DateTime.UtcNow - item.DateLastRefreshed >= _viewRefreshInterval;
- if (!refresh && item.DisplayParentId != Guid.Empty)
+ if (!refresh && !item.DisplayParentId.Equals(Guid.Empty))
{
var displayParent = GetItemById(item.DisplayParentId);
refresh = displayParent != null && displayParent.DateLastSaved > item.DateLastRefreshed;
@@ -2346,6 +2379,13 @@ namespace Emby.Server.Implementations.Library
return item;
}
+ public void AddExternalSubtitleStreams(List<MediaStream> streams,
+ string videoPath,
+ string[] files)
+ {
+ new SubtitleResolver(BaseItem.LocalizationManager, _fileSystem).AddExternalSubtitleStreams(streams, videoPath, streams.Count, files);
+ }
+
public bool IsVideoFile(string path, LibraryOptions libraryOptions)
{
var resolver = new VideoResolver(GetNamingOptions());
@@ -2370,19 +2410,25 @@ namespace Emby.Server.Implementations.Library
public int? GetSeasonNumberFromPath(string path)
{
- return new SeasonPathParser(GetNamingOptions(), new RegexProvider()).Parse(path, true, true).SeasonNumber;
+ return new SeasonPathParser(GetNamingOptions()).Parse(path, true, true).SeasonNumber;
}
- public bool FillMissingEpisodeNumbersFromPath(Episode episode)
+ public bool FillMissingEpisodeNumbersFromPath(Episode episode, bool forceRefresh)
{
+ var series = episode.Series;
+ bool? isAbsoluteNaming = series == null ? false : string.Equals(series.DisplayOrder, "absolute", StringComparison.OrdinalIgnoreCase);
+ if (!isAbsoluteNaming.Value)
+ {
+ // In other words, no filter applied
+ isAbsoluteNaming = null;
+ }
+
var resolver = new EpisodeResolver(GetNamingOptions());
var isFolder = episode.VideoType == VideoType.BluRay || episode.VideoType == VideoType.Dvd;
- var locationType = episode.LocationType;
-
- var episodeInfo = locationType == LocationType.FileSystem || locationType == LocationType.Offline ?
- resolver.Resolve(episode.Path, isFolder) :
+ var episodeInfo = episode.IsFileProtocol ?
+ resolver.Resolve(episode.Path, isFolder, null, null, isAbsoluteNaming) :
new Emby.Naming.TV.EpisodeInfo();
if (episodeInfo == null)
@@ -2428,105 +2474,67 @@ namespace Emby.Server.Implementations.Library
changed = true;
}
}
-
- if (!episode.ParentIndexNumber.HasValue)
- {
- var season = episode.Season;
-
- if (season != null)
- {
- episode.ParentIndexNumber = season.IndexNumber;
- }
-
- if (episode.ParentIndexNumber.HasValue)
- {
- changed = true;
- }
- }
}
else
{
- if (!episode.IndexNumber.HasValue)
+ if (!episode.IndexNumber.HasValue || forceRefresh)
{
- episode.IndexNumber = episodeInfo.EpisodeNumber;
-
- if (episode.IndexNumber.HasValue)
+ if (episode.IndexNumber != episodeInfo.EpisodeNumber)
{
changed = true;
}
+ episode.IndexNumber = episodeInfo.EpisodeNumber;
}
- if (!episode.IndexNumberEnd.HasValue)
+ if (!episode.IndexNumberEnd.HasValue || forceRefresh)
{
- episode.IndexNumberEnd = episodeInfo.EndingEpsiodeNumber;
-
- if (episode.IndexNumberEnd.HasValue)
+ if (episode.IndexNumberEnd != episodeInfo.EndingEpsiodeNumber)
{
changed = true;
}
+ episode.IndexNumberEnd = episodeInfo.EndingEpsiodeNumber;
}
- if (!episode.ParentIndexNumber.HasValue)
+ if (!episode.ParentIndexNumber.HasValue || forceRefresh)
{
- episode.ParentIndexNumber = episodeInfo.SeasonNumber;
-
- if (!episode.ParentIndexNumber.HasValue)
- {
- var season = episode.Season;
-
- if (season != null)
- {
- episode.ParentIndexNumber = season.IndexNumber;
- }
- }
-
- if (episode.ParentIndexNumber.HasValue)
+ if (episode.ParentIndexNumber != episodeInfo.SeasonNumber)
{
changed = true;
}
+ episode.ParentIndexNumber = episodeInfo.SeasonNumber;
}
}
- return changed;
- }
-
- public NamingOptions GetNamingOptions()
- {
- return GetNamingOptions(true);
- }
-
- public NamingOptions GetNamingOptions(bool allowOptimisticEpisodeDetection)
- {
- if (!allowOptimisticEpisodeDetection)
+ if (!episode.ParentIndexNumber.HasValue)
{
- if (_namingOptionsWithoutOptimisticEpisodeDetection == null)
- {
- var namingOptions = new ExtendedNamingOptions();
+ var season = episode.Season;
- InitNamingOptions(namingOptions);
- namingOptions.EpisodeExpressions = namingOptions.EpisodeExpressions
- .Where(i => i.IsNamed && !i.IsOptimistic)
- .ToList();
-
- _namingOptionsWithoutOptimisticEpisodeDetection = namingOptions;
+ if (season != null)
+ {
+ episode.ParentIndexNumber = season.IndexNumber;
}
- return _namingOptionsWithoutOptimisticEpisodeDetection;
+ if (episode.ParentIndexNumber.HasValue)
+ {
+ changed = true;
+ }
}
+ return changed;
+ }
+
+ public NamingOptions GetNamingOptions()
+ {
return GetNamingOptionsInternal();
}
- private NamingOptions _namingOptionsWithoutOptimisticEpisodeDetection;
private NamingOptions _namingOptions;
private string[] _videoFileExtensions;
private NamingOptions GetNamingOptionsInternal()
{
if (_namingOptions == null)
{
- var options = new ExtendedNamingOptions();
-
- InitNamingOptions(options);
+ var options = new NamingOptions();
_namingOptions = options;
_videoFileExtensions = _namingOptions.VideoFileExtensions.ToArray();
@@ -2535,27 +2543,6 @@ namespace Emby.Server.Implementations.Library
return _namingOptions;
}
- private void InitNamingOptions(NamingOptions options)
- {
- // These cause apps to have problems
- options.AudioFileExtensions.Remove(".m3u");
- options.AudioFileExtensions.Remove(".wpl");
-
- //if (!libraryOptions.EnableArchiveMediaFiles)
- {
- options.AudioFileExtensions.Remove(".rar");
- options.AudioFileExtensions.Remove(".zip");
- }
-
- //if (!libraryOptions.EnableArchiveMediaFiles)
- {
- options.VideoFileExtensions.Remove(".rar");
- options.VideoFileExtensions.Remove(".zip");
- }
-
- options.VideoFileExtensions.Add(".tp");
- }
-
public ItemLookupInfo ParseName(string name)
{
var resolver = new VideoResolver(GetNamingOptions());
@@ -2606,12 +2593,11 @@ namespace Emby.Server.Implementations.Library
{
video = dbItem;
}
- else
- {
- // item is new
- video.ExtraType = ExtraType.Trailer;
- }
- video.TrailerTypes = new List<TrailerType> { TrailerType.LocalTrailer };
+
+ video.ParentId = Guid.Empty;
+ video.OwnerId = owner.Id;
+ video.ExtraType = ExtraType.Trailer;
+ video.TrailerTypes = new [] { TrailerType.LocalTrailer };
return video;
@@ -2625,7 +2611,7 @@ namespace Emby.Server.Implementations.Library
{
var namingOptions = GetNamingOptions();
- var files = fileSystemChildren.Where(i => i.IsDirectory)
+ var files = owner.IsInMixedFolder ? new List<FileSystemMetadata>() : fileSystemChildren.Where(i => i.IsDirectory)
.Where(i => ExtrasSubfolderNames.Contains(i.Name ?? string.Empty, StringComparer.OrdinalIgnoreCase))
.SelectMany(i => _fileSystem.GetFiles(i.FullName, _videoFileExtensions, false, false))
.ToList();
@@ -2653,6 +2639,9 @@ namespace Emby.Server.Implementations.Library
video = dbItem;
}
+ video.ParentId = Guid.Empty;
+ video.OwnerId = owner.Id;
+
SetExtraTypeFromFilename(video);
return video;
@@ -2756,7 +2745,7 @@ namespace Emby.Server.Implementations.Library
private void SetExtraTypeFromFilename(Video item)
{
- var resolver = new ExtraResolver(GetNamingOptions(), new RegexProvider());
+ var resolver = new ExtraResolver(GetNamingOptions());
var result = resolver.GetExtraInfo(item.Path);
@@ -2841,7 +2830,7 @@ namespace Emby.Server.Implementations.Library
ItemRepository.UpdatePeople(item.Id, people);
}
- public async Task<ItemImageInfo> ConvertImageToLocal(IHasMetadata item, ItemImageInfo image, int imageIndex)
+ public async Task<ItemImageInfo> ConvertImageToLocal(BaseItem item, ItemImageInfo image, int imageIndex)
{
foreach (var url in image.Path.Split('|'))
{
@@ -2872,7 +2861,7 @@ namespace Emby.Server.Implementations.Library
throw new InvalidOperationException();
}
- public void AddVirtualFolder(string name, string collectionType, LibraryOptions options, bool refreshLibrary)
+ public async Task AddVirtualFolder(string name, string collectionType, LibraryOptions options, bool refreshLibrary)
{
if (string.IsNullOrWhiteSpace(name))
{
@@ -2910,7 +2899,7 @@ namespace Emby.Server.Implementations.Library
{
var path = Path.Combine(virtualFolderPath, collectionType + ".collection");
- _fileSystem.WriteAllBytes(path, new byte[] { });
+ _fileSystem.WriteAllBytes(path, Array.Empty<byte>());
}
CollectionFolder.SaveLibraryOptions(virtualFolderPath, options);
@@ -2925,26 +2914,30 @@ namespace Emby.Server.Implementations.Library
}
finally
{
- Task.Run(() =>
+ if (refreshLibrary)
{
- // No need to start if scanning the library because it will handle it
- if (refreshLibrary)
- {
- ValidateMediaLibrary(new SimpleProgress<double>(), CancellationToken.None);
- }
- else
- {
- // Need to add a delay here or directory watchers may still pick up the changes
- var task = Task.Delay(1000);
- // Have to block here to allow exceptions to bubble
- Task.WaitAll(task);
+ await ValidateTopLibraryFolders(CancellationToken.None).ConfigureAwait(false);
- _libraryMonitorFactory().Start();
- }
- });
+ StartScanInBackground();
+ }
+ else
+ {
+ // Need to add a delay here or directory watchers may still pick up the changes
+ await Task.Delay(1000).ConfigureAwait(false);
+ _libraryMonitorFactory().Start();
+ }
}
}
+ private void StartScanInBackground()
+ {
+ Task.Run(() =>
+ {
+ // No need to start if scanning the library because it will handle it
+ ValidateMediaLibrary(new SimpleProgress<double>(), CancellationToken.None);
+ });
+ }
+
private bool ValidateNetworkPath(string path)
{
//if (Environment.OSVersion.Platform == PlatformID.Win32NT)
@@ -3003,7 +2996,7 @@ namespace Emby.Server.Implementations.Library
lnk = Path.Combine(virtualFolderPath, shortcutFilename + ShortcutFileExtension);
}
- _fileSystem.CreateShortcut(lnk, path);
+ _fileSystem.CreateShortcut(lnk, _appHost.ReverseVirtualPath(path));
RemoveContentTypeOverrides(path);
@@ -3079,7 +3072,7 @@ namespace Emby.Server.Implementations.Library
}
}
- public void RemoveVirtualFolder(string name, bool refreshLibrary)
+ public async Task RemoveVirtualFolder(string name, bool refreshLibrary)
{
if (string.IsNullOrWhiteSpace(name))
{
@@ -3103,23 +3096,20 @@ namespace Emby.Server.Implementations.Library
}
finally
{
- Task.Run(() =>
+ CollectionFolder.OnCollectionFolderChange();
+
+ if (refreshLibrary)
{
- // No need to start if scanning the library because it will handle it
- if (refreshLibrary)
- {
- ValidateMediaLibrary(new SimpleProgress<double>(), CancellationToken.None);
- }
- else
- {
- // Need to add a delay here or directory watchers may still pick up the changes
- var task = Task.Delay(1000);
- // Have to block here to allow exceptions to bubble
- Task.WaitAll(task);
+ await ValidateTopLibraryFolders(CancellationToken.None).ConfigureAwait(false);
- _libraryMonitorFactory().Start();
- }
- });
+ StartScanInBackground();
+ }
+ else
+ {
+ // Need to add a delay here or directory watchers may still pick up the changes
+ await Task.Delay(1000).ConfigureAwait(false);
+ _libraryMonitorFactory().Start();
+ }
}
}
@@ -3157,7 +3147,7 @@ namespace Emby.Server.Implementations.Library
public void RemoveMediaPath(string virtualFolderName, string mediaPath)
{
- if (string.IsNullOrWhiteSpace(mediaPath))
+ if (string.IsNullOrEmpty(mediaPath))
{
throw new ArgumentNullException("mediaPath");
}
@@ -3172,7 +3162,7 @@ namespace Emby.Server.Implementations.Library
var shortcut = _fileSystem.GetFilePaths(virtualFolderPath, true)
.Where(i => string.Equals(ShortcutFileExtension, Path.GetExtension(i), StringComparison.OrdinalIgnoreCase))
- .FirstOrDefault(f => _fileSystem.ResolveShortcut(f).Equals(mediaPath, StringComparison.OrdinalIgnoreCase));
+ .FirstOrDefault(f => _appHost.ExpandVirtualPath(_fileSystem.ResolveShortcut(f)).Equals(mediaPath, StringComparison.OrdinalIgnoreCase));
if (!string.IsNullOrEmpty(shortcut))
{