aboutsummaryrefslogtreecommitdiff
path: root/MediaBrowser.Server.Implementations/Library
diff options
context:
space:
mode:
Diffstat (limited to 'MediaBrowser.Server.Implementations/Library')
-rw-r--r--MediaBrowser.Server.Implementations/Library/CoreResolutionIgnoreRule.cs148
-rw-r--r--MediaBrowser.Server.Implementations/Library/LibraryManager.cs3067
-rw-r--r--MediaBrowser.Server.Implementations/Library/LocalTrailerPostScanTask.cs102
-rw-r--r--MediaBrowser.Server.Implementations/Library/MediaSourceManager.cs648
-rw-r--r--MediaBrowser.Server.Implementations/Library/MusicManager.cs157
-rw-r--r--MediaBrowser.Server.Implementations/Library/PathExtensions.cs45
-rw-r--r--MediaBrowser.Server.Implementations/Library/ResolverHelper.cs183
-rw-r--r--MediaBrowser.Server.Implementations/Library/Resolvers/Audio/AudioResolver.cs68
-rw-r--r--MediaBrowser.Server.Implementations/Library/Resolvers/Audio/MusicAlbumResolver.cs173
-rw-r--r--MediaBrowser.Server.Implementations/Library/Resolvers/Audio/MusicArtistResolver.cs94
-rw-r--r--MediaBrowser.Server.Implementations/Library/Resolvers/BaseVideoResolver.cs297
-rw-r--r--MediaBrowser.Server.Implementations/Library/Resolvers/FolderResolver.cs56
-rw-r--r--MediaBrowser.Server.Implementations/Library/Resolvers/ItemResolver.cs62
-rw-r--r--MediaBrowser.Server.Implementations/Library/Resolvers/Movies/BoxSetResolver.cs77
-rw-r--r--MediaBrowser.Server.Implementations/Library/Resolvers/Movies/MovieResolver.cs541
-rw-r--r--MediaBrowser.Server.Implementations/Library/Resolvers/PhotoAlbumResolver.cs56
-rw-r--r--MediaBrowser.Server.Implementations/Library/Resolvers/PhotoResolver.cs103
-rw-r--r--MediaBrowser.Server.Implementations/Library/Resolvers/PlaylistResolver.cs42
-rw-r--r--MediaBrowser.Server.Implementations/Library/Resolvers/SpecialFolderResolver.cs85
-rw-r--r--MediaBrowser.Server.Implementations/Library/Resolvers/TV/EpisodeResolver.cs75
-rw-r--r--MediaBrowser.Server.Implementations/Library/Resolvers/TV/SeasonResolver.cs62
-rw-r--r--MediaBrowser.Server.Implementations/Library/Resolvers/TV/SeriesResolver.cs251
-rw-r--r--MediaBrowser.Server.Implementations/Library/Resolvers/VideoResolver.cs45
-rw-r--r--MediaBrowser.Server.Implementations/Library/SearchEngine.cs280
-rw-r--r--MediaBrowser.Server.Implementations/Library/UserViewManager.cs292
-rw-r--r--MediaBrowser.Server.Implementations/Library/Validators/ArtistsPostScanTask.cs44
-rw-r--r--MediaBrowser.Server.Implementations/Library/Validators/ArtistsValidator.cs84
-rw-r--r--MediaBrowser.Server.Implementations/Library/Validators/GameGenresPostScanTask.cs45
-rw-r--r--MediaBrowser.Server.Implementations/Library/Validators/GameGenresValidator.cs74
-rw-r--r--MediaBrowser.Server.Implementations/Library/Validators/GenresPostScanTask.cs42
-rw-r--r--MediaBrowser.Server.Implementations/Library/Validators/GenresValidator.cs75
-rw-r--r--MediaBrowser.Server.Implementations/Library/Validators/MusicGenresPostScanTask.cs45
-rw-r--r--MediaBrowser.Server.Implementations/Library/Validators/MusicGenresValidator.cs75
-rw-r--r--MediaBrowser.Server.Implementations/Library/Validators/PeopleValidator.cs172
-rw-r--r--MediaBrowser.Server.Implementations/Library/Validators/StudiosPostScanTask.cs45
-rw-r--r--MediaBrowser.Server.Implementations/Library/Validators/StudiosValidator.cs74
-rw-r--r--MediaBrowser.Server.Implementations/Library/Validators/YearsPostScanTask.cs55
37 files changed, 0 insertions, 7839 deletions
diff --git a/MediaBrowser.Server.Implementations/Library/CoreResolutionIgnoreRule.cs b/MediaBrowser.Server.Implementations/Library/CoreResolutionIgnoreRule.cs
deleted file mode 100644
index f20d87c4b..000000000
--- a/MediaBrowser.Server.Implementations/Library/CoreResolutionIgnoreRule.cs
+++ /dev/null
@@ -1,148 +0,0 @@
-using MediaBrowser.Model.Extensions;
-using MediaBrowser.Controller.Entities;
-using MediaBrowser.Controller.Library;
-using MediaBrowser.Controller.Resolvers;
-using System;
-using System.Collections.Generic;
-using System.IO;
-using System.Linq;
-using MediaBrowser.Common.IO;
-using MediaBrowser.Controller.IO;
-using MediaBrowser.Model.IO;
-
-namespace MediaBrowser.Server.Implementations.Library
-{
- /// <summary>
- /// Provides the core resolver ignore rules
- /// </summary>
- public class CoreResolutionIgnoreRule : IResolverIgnoreRule
- {
- private readonly IFileSystem _fileSystem;
- private readonly ILibraryManager _libraryManager;
-
- /// <summary>
- /// Any folder named in this list will be ignored - can be added to at runtime for extensibility
- /// </summary>
- public static readonly List<string> IgnoreFolders = new List<string>
- {
- "metadata",
- "ps3_update",
- "ps3_vprm",
- "extrafanart",
- "extrathumbs",
- ".actors",
- ".wd_tv",
-
- // Synology
- "@eaDir",
- "eaDir",
- "#recycle"
-
- };
-
- public CoreResolutionIgnoreRule(IFileSystem fileSystem, ILibraryManager libraryManager)
- {
- _fileSystem = fileSystem;
- _libraryManager = libraryManager;
- }
-
- /// <summary>
- /// Shoulds the ignore.
- /// </summary>
- /// <param name="fileInfo">The file information.</param>
- /// <param name="parent">The parent.</param>
- /// <returns><c>true</c> if XXXX, <c>false</c> otherwise</returns>
- public bool ShouldIgnore(FileSystemMetadata fileInfo, BaseItem parent)
- {
- var filename = fileInfo.Name;
- var isHidden = fileInfo.IsHidden;
- var path = fileInfo.FullName;
-
- // Handle mac .DS_Store
- // https://github.com/MediaBrowser/MediaBrowser/issues/427
- if (filename.IndexOf("._", StringComparison.OrdinalIgnoreCase) == 0)
- {
- return true;
- }
-
- // Ignore hidden files and folders
- if (isHidden)
- {
- if (parent == null)
- {
- var parentFolderName = Path.GetFileName(Path.GetDirectoryName(path));
-
- if (string.Equals(parentFolderName, BaseItem.ThemeSongsFolderName, StringComparison.OrdinalIgnoreCase))
- {
- return false;
- }
- if (string.Equals(parentFolderName, BaseItem.ThemeVideosFolderName, StringComparison.OrdinalIgnoreCase))
- {
- return false;
- }
- }
-
- // Sometimes these are marked hidden
- if (_fileSystem.IsRootPath(path))
- {
- return false;
- }
-
- return true;
- }
-
- if (fileInfo.IsDirectory)
- {
- // Ignore any folders in our list
- if (IgnoreFolders.Contains(filename, StringComparer.OrdinalIgnoreCase))
- {
- return true;
- }
-
- if (parent != null)
- {
- // Ignore trailer folders but allow it at the collection level
- if (string.Equals(filename, BaseItem.TrailerFolderName, StringComparison.OrdinalIgnoreCase) &&
- !(parent is AggregateFolder) && !(parent is UserRootFolder))
- {
- return true;
- }
-
- if (string.Equals(filename, BaseItem.ThemeVideosFolderName, StringComparison.OrdinalIgnoreCase))
- {
- return true;
- }
-
- if (string.Equals(filename, BaseItem.ThemeSongsFolderName, StringComparison.OrdinalIgnoreCase))
- {
- return true;
- }
- }
- }
- else
- {
- if (parent != null)
- {
- // Don't resolve these into audio files
- if (string.Equals(_fileSystem.GetFileNameWithoutExtension(filename), BaseItem.ThemeSongFilename) && _libraryManager.IsAudioFile(filename))
- {
- return true;
- }
- }
-
- // Ignore samples
- var sampleFilename = " " + filename.Replace(".", " ", StringComparison.OrdinalIgnoreCase)
- .Replace("-", " ", StringComparison.OrdinalIgnoreCase)
- .Replace("_", " ", StringComparison.OrdinalIgnoreCase)
- .Replace("!", " ", StringComparison.OrdinalIgnoreCase);
-
- if (sampleFilename.IndexOf(" sample ", StringComparison.OrdinalIgnoreCase) != -1)
- {
- return true;
- }
- }
-
- return false;
- }
- }
-}
diff --git a/MediaBrowser.Server.Implementations/Library/LibraryManager.cs b/MediaBrowser.Server.Implementations/Library/LibraryManager.cs
deleted file mode 100644
index 18feaa849..000000000
--- a/MediaBrowser.Server.Implementations/Library/LibraryManager.cs
+++ /dev/null
@@ -1,3067 +0,0 @@
-using MediaBrowser.Common.Extensions;
-using MediaBrowser.Common.Progress;
-using MediaBrowser.Controller.Configuration;
-using MediaBrowser.Controller.Entities;
-using MediaBrowser.Controller.Entities.Audio;
-using MediaBrowser.Controller.Entities.TV;
-using MediaBrowser.Controller.IO;
-using MediaBrowser.Controller.Library;
-using MediaBrowser.Controller.Persistence;
-using MediaBrowser.Controller.Providers;
-using MediaBrowser.Controller.Resolvers;
-using MediaBrowser.Controller.Sorting;
-using MediaBrowser.Model.Configuration;
-using MediaBrowser.Model.Entities;
-using MediaBrowser.Model.Logging;
-using MediaBrowser.Model.Querying;
-using MediaBrowser.Naming.Audio;
-using MediaBrowser.Naming.Common;
-using MediaBrowser.Naming.TV;
-using MediaBrowser.Naming.Video;
-using MediaBrowser.Server.Implementations.Library.Validators;
-using MediaBrowser.Server.Implementations.Logging;
-using MediaBrowser.Server.Implementations.ScheduledTasks;
-using System;
-using System.Collections.Concurrent;
-using System.Collections.Generic;
-using System.Globalization;
-using System.IO;
-using System.Linq;
-using System.Net;
-using System.Threading;
-using System.Threading.Tasks;
-using MediaBrowser.Model.IO;
-using MediaBrowser.Controller.Channels;
-using MediaBrowser.Model.Channels;
-using MediaBrowser.Model.Dto;
-using MediaBrowser.Model.Extensions;
-using MediaBrowser.Model.Library;
-using MediaBrowser.Model.Net;
-using MediaBrowser.Server.Implementations.Library.Resolvers;
-using SortOrder = MediaBrowser.Model.Entities.SortOrder;
-using VideoResolver = MediaBrowser.Naming.Video.VideoResolver;
-using MediaBrowser.Common.Configuration;
-using MediaBrowser.Common.IO;
-using MediaBrowser.Model.Tasks;
-
-namespace MediaBrowser.Server.Implementations.Library
-{
- /// <summary>
- /// Class LibraryManager
- /// </summary>
- public class LibraryManager : ILibraryManager
- {
- /// <summary>
- /// Gets or sets the postscan tasks.
- /// </summary>
- /// <value>The postscan tasks.</value>
- private ILibraryPostScanTask[] PostscanTasks { get; set; }
-
- /// <summary>
- /// Gets the intro providers.
- /// </summary>
- /// <value>The intro providers.</value>
- private IIntroProvider[] IntroProviders { get; set; }
-
- /// <summary>
- /// Gets the list of entity resolution ignore rules
- /// </summary>
- /// <value>The entity resolution ignore rules.</value>
- 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>
- private IItemResolver[] EntityResolvers { get; set; }
- private IMultiItemResolver[] MultiItemResolvers { get; set; }
-
- /// <summary>
- /// Gets or sets the comparers.
- /// </summary>
- /// <value>The comparers.</value>
- private IBaseItemComparer[] Comparers { get; set; }
-
- /// <summary>
- /// Gets the active item repository
- /// </summary>
- /// <value>The item repository.</value>
- public IItemRepository ItemRepository { get; set; }
-
- /// <summary>
- /// Occurs when [item added].
- /// </summary>
- public event EventHandler<ItemChangeEventArgs> ItemAdded;
-
- /// <summary>
- /// Occurs when [item updated].
- /// </summary>
- public event EventHandler<ItemChangeEventArgs> ItemUpdated;
-
- /// <summary>
- /// Occurs when [item removed].
- /// </summary>
- public event EventHandler<ItemChangeEventArgs> ItemRemoved;
-
- /// <summary>
- /// The _logger
- /// </summary>
- private readonly ILogger _logger;
-
- /// <summary>
- /// The _task manager
- /// </summary>
- private readonly ITaskManager _taskManager;
-
- /// <summary>
- /// The _user manager
- /// </summary>
- private readonly IUserManager _userManager;
-
- /// <summary>
- /// The _user data repository
- /// </summary>
- private readonly IUserDataManager _userDataRepository;
-
- /// <summary>
- /// Gets or sets the configuration manager.
- /// </summary>
- /// <value>The configuration manager.</value>
- private IServerConfigurationManager ConfigurationManager { get; set; }
-
- /// <summary>
- /// 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.
- /// </summary>
- /// <value>The by reference items.</value>
- private ConcurrentDictionary<Guid, BaseItem> ByReferenceItems { get; set; }
-
- private readonly Func<ILibraryMonitor> _libraryMonitorFactory;
- private readonly Func<IProviderManager> _providerManagerFactory;
- private readonly Func<IUserViewManager> _userviewManager;
- public bool IsScanRunning { get; private set; }
-
- /// <summary>
- /// The _library items cache
- /// </summary>
- private readonly ConcurrentDictionary<Guid, BaseItem> _libraryItemsCache;
- /// <summary>
- /// Gets the library items cache.
- /// </summary>
- /// <value>The library items cache.</value>
- private ConcurrentDictionary<Guid, BaseItem> LibraryItemsCache
- {
- get
- {
- return _libraryItemsCache;
- }
- }
-
- private readonly IFileSystem _fileSystem;
-
- /// <summary>
- /// Initializes a new instance of the <see cref="LibraryManager" /> class.
- /// </summary>
- /// <param name="logger">The logger.</param>
- /// <param name="taskManager">The task manager.</param>
- /// <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)
- {
- _logger = logger;
- _taskManager = taskManager;
- _userManager = userManager;
- ConfigurationManager = configurationManager;
- _userDataRepository = userDataRepository;
- _libraryMonitorFactory = libraryMonitorFactory;
- _fileSystem = fileSystem;
- _providerManagerFactory = providerManagerFactory;
- _userviewManager = userviewManager;
- ByReferenceItems = new ConcurrentDictionary<Guid, BaseItem>();
- _libraryItemsCache = new ConcurrentDictionary<Guid, BaseItem>();
-
- ConfigurationManager.ConfigurationUpdated += ConfigurationUpdated;
-
- RecordConfigurationValues(configurationManager.Configuration);
- }
-
- /// <summary>
- /// Adds the parts.
- /// </summary>
- /// <param name="rules">The rules.</param>
- /// <param name="pluginFolders">The plugin folders.</param>
- /// <param name="resolvers">The resolvers.</param>
- /// <param name="introProviders">The intro providers.</param>
- /// <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();
- Comparers = itemComparers.ToArray();
-
- PostscanTasks = postscanTasks.OrderBy(i =>
- {
- var hasOrder = i as IHasOrder;
-
- return hasOrder == null ? 0 : hasOrder.Order;
-
- }).ToArray();
- }
-
- /// <summary>
- /// The _root folder
- /// </summary>
- private volatile AggregateFolder _rootFolder;
- /// <summary>
- /// The _root folder sync lock
- /// </summary>
- private readonly object _rootFolderSyncLock = new object();
- /// <summary>
- /// Gets the root folder.
- /// </summary>
- /// <value>The root folder.</value>
- public AggregateFolder RootFolder
- {
- get
- {
- if (_rootFolder == null)
- {
- lock (_rootFolderSyncLock)
- {
- if (_rootFolder == null)
- {
- _rootFolder = CreateRootFolder();
- }
- }
- }
- return _rootFolder;
- }
- }
-
- /// <summary>
- /// The _season zero display name
- /// </summary>
- private string _seasonZeroDisplayName;
-
- private bool _wizardCompleted;
- /// <summary>
- /// Records the configuration values.
- /// </summary>
- /// <param name="configuration">The configuration.</param>
- private void RecordConfigurationValues(ServerConfiguration configuration)
- {
- _seasonZeroDisplayName = configuration.SeasonZeroDisplayName;
- _wizardCompleted = configuration.IsStartupWizardCompleted;
- }
-
- /// <summary>
- /// Configurations the updated.
- /// </summary>
- /// <param name="sender">The sender.</param>
- /// <param name="e">The <see cref="EventArgs" /> instance containing the event data.</param>
- void ConfigurationUpdated(object sender, EventArgs e)
- {
- var config = ConfigurationManager.Configuration;
-
- var newSeasonZeroName = ConfigurationManager.Configuration.SeasonZeroDisplayName;
- var seasonZeroNameChanged = !string.Equals(_seasonZeroDisplayName, newSeasonZeroName, StringComparison.Ordinal);
- var wizardChanged = config.IsStartupWizardCompleted != _wizardCompleted;
-
- RecordConfigurationValues(config);
-
- if (seasonZeroNameChanged || wizardChanged)
- {
- _taskManager.CancelIfRunningAndQueue<RefreshMediaLibraryTask>();
- }
-
- if (seasonZeroNameChanged)
- {
- Task.Run(async () =>
- {
- await UpdateSeasonZeroNames(newSeasonZeroName, CancellationToken.None).ConfigureAwait(false);
-
- });
- }
- }
-
- /// <summary>
- /// Updates the season zero names.
- /// </summary>
- /// <param name="newName">The new name.</param>
- /// <param name="cancellationToken">The cancellation token.</param>
- /// <returns>Task.</returns>
- private async Task UpdateSeasonZeroNames(string newName, CancellationToken cancellationToken)
- {
- var seasons = GetItemList(new InternalItemsQuery
- {
- IncludeItemTypes = new[] { typeof(Season).Name },
- Recursive = true,
- IndexNumber = 0
-
- }).Cast<Season>()
- .Where(i => !string.Equals(i.Name, newName, StringComparison.Ordinal))
- .ToList();
-
- foreach (var season in seasons)
- {
- season.Name = newName;
-
- try
- {
- await UpdateItem(season, ItemUpdateType.MetadataDownload, cancellationToken).ConfigureAwait(false);
- }
- catch (Exception ex)
- {
- _logger.ErrorException("Error saving {0}", ex, season.Path);
- }
- }
- }
-
- public void RegisterItem(BaseItem item)
- {
- if (item == null)
- {
- throw new ArgumentNullException("item");
- }
- RegisterItem(item.Id, item);
- }
-
- private void RegisterItem(Guid id, BaseItem item)
- {
- if (item is IItemByName)
- {
- if (!(item is MusicArtist))
- {
- return;
- }
- }
-
- if (item.IsFolder)
- {
- if (!(item is ICollectionFolder) && !(item is UserView) && !(item is Channel) && !(item is AggregateFolder))
- {
- if (item.SourceType != SourceType.Library)
- {
- return;
- }
- }
- }
- else
- {
- if (item is Photo)
- {
- return;
- }
- }
-
- LibraryItemsCache.AddOrUpdate(id, item, delegate { return item; });
- }
-
- public async Task DeleteItem(BaseItem item, DeleteOptions options)
- {
- if (item == null)
- {
- throw new ArgumentNullException("item");
- }
-
- _logger.Debug("Deleting item, Type: {0}, Name: {1}, Path: {2}, Id: {3}",
- item.GetType().Name,
- item.Name ?? "Unknown name",
- item.Path ?? string.Empty,
- item.Id);
-
- var parent = item.Parent;
-
- var locationType = item.LocationType;
-
- var children = item.IsFolder
- ? ((Folder)item).GetRecursiveChildren(false).ToList()
- : new List<BaseItem>();
-
- foreach (var metadataPath in GetMetadataPaths(item, children))
- {
- _logger.Debug("Deleting path {0}", metadataPath);
-
- try
- {
- _fileSystem.DeleteDirectory(metadataPath, true);
- }
- catch (DirectoryNotFoundException)
- {
-
- }
- catch (Exception ex)
- {
- _logger.ErrorException("Error deleting {0}", ex, metadataPath);
- }
- }
-
- if (options.DeleteFileLocation && locationType != LocationType.Remote && locationType != LocationType.Virtual)
- {
- foreach (var path in item.GetDeletePaths().ToList())
- {
- if (_fileSystem.DirectoryExists(path))
- {
- _logger.Debug("Deleting path {0}", path);
- _fileSystem.DeleteDirectory(path, true);
- }
- else if (_fileSystem.FileExists(path))
- {
- _logger.Debug("Deleting path {0}", path);
- _fileSystem.DeleteFile(path);
- }
- }
-
- if (parent != null)
- {
- await parent.ValidateChildren(new Progress<double>(), CancellationToken.None)
- .ConfigureAwait(false);
- }
- }
- else if (parent != null)
- {
- parent.RemoveChild(item);
- }
-
- await ItemRepository.DeleteItem(item.Id, CancellationToken.None).ConfigureAwait(false);
- foreach (var child in children)
- {
- await ItemRepository.DeleteItem(child.Id, CancellationToken.None).ConfigureAwait(false);
- }
-
- BaseItem removed;
- _libraryItemsCache.TryRemove(item.Id, out removed);
-
- ReportItemRemoved(item);
- }
-
- private IEnumerable<string> GetMetadataPaths(BaseItem item, IEnumerable<BaseItem> children)
- {
- var list = new List<string>
- {
- item.GetInternalMetadataPath()
- };
-
- list.AddRange(children.Select(i => i.GetInternalMetadataPath()));
-
- return list;
- }
-
- /// <summary>
- /// Resolves the item.
- /// </summary>
- /// <param name="args">The args.</param>
- /// <param name="resolvers">The resolvers.</param>
- /// <returns>BaseItem.</returns>
- private BaseItem ResolveItem(ItemResolveArgs args, IItemResolver[] resolvers)
- {
- var item = (resolvers ?? EntityResolvers).Select(r => Resolve(args, r))
- .FirstOrDefault(i => i != null);
-
- if (item != null)
- {
- ResolverHelper.SetInitialItemValues(item, args, _fileSystem, this);
- }
-
- return item;
- }
-
- private BaseItem Resolve(ItemResolveArgs args, IItemResolver resolver)
- {
- try
- {
- return resolver.ResolvePath(args);
- }
- catch (Exception ex)
- {
- _logger.ErrorException("Error in {0} resolving {1}", ex, resolver.GetType().Name, args.Path);
- return null;
- }
- }
-
- public Guid GetNewItemId(string key, Type type)
- {
- if (string.IsNullOrWhiteSpace(key))
- {
- throw new ArgumentNullException("key");
- }
- if (type == null)
- {
- throw new ArgumentNullException("type");
- }
-
- if (ConfigurationManager.Configuration.EnableLocalizedGuids && key.StartsWith(ConfigurationManager.ApplicationPaths.ProgramDataPath))
- {
- // Try to normalize paths located underneath program-data in an attempt to make them more portable
- key = key.Substring(ConfigurationManager.ApplicationPaths.ProgramDataPath.Length)
- .TrimStart(new[] { '/', '\\' })
- .Replace("/", "\\");
- }
-
- if (!ConfigurationManager.Configuration.EnableCaseSensitiveItemIds)
- {
- key = key.ToLower();
- }
-
- key = type.FullName + key;
-
- return key.GetMD5();
- }
-
- /// <summary>
- /// Ensure supplied item has only one instance throughout
- /// </summary>
- /// <param name="item">The item.</param>
- /// <returns>The proper instance to the item</returns>
- 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;
- }
-
- public BaseItem ResolvePath(FileSystemMetadata fileInfo,
- Folder parent = null)
- {
- return ResolvePath(fileInfo, new DirectoryService(_logger, _fileSystem), null, parent);
- }
-
- private BaseItem ResolvePath(FileSystemMetadata fileInfo,
- IDirectoryService directoryService,
- IItemResolver[] resolvers,
- Folder parent = null,
- string collectionType = null,
- LibraryOptions libraryOptions = null)
- {
- if (fileInfo == null)
- {
- throw new ArgumentNullException("fileInfo");
- }
-
- var fullPath = fileInfo.FullName;
-
- if (string.IsNullOrWhiteSpace(collectionType) && parent != null)
- {
- collectionType = GetContentTypeOverride(fullPath, true);
- }
-
- var args = new ItemResolveArgs(ConfigurationManager.ApplicationPaths, directoryService)
- {
- Parent = parent,
- Path = fullPath,
- FileInfo = fileInfo,
- CollectionType = collectionType,
- LibraryOptions = libraryOptions
- };
-
- // Return null if ignore rules deem that we should do so
- if (IgnoreFile(args.FileInfo, args.Parent))
- {
- return null;
- }
-
- // Gather child folder and files
- if (args.IsDirectory)
- {
- var isPhysicalRoot = args.IsPhysicalRoot;
-
- // When resolving the root, we need it's grandchildren (children of user views)
- 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)
- {
- var paths = NormalizeRootPathList(fileSystemDictionary.Values);
-
- fileSystemDictionary = paths.ToDictionary(i => i.FullName);
- }
-
- args.FileSystemDictionary = fileSystemDictionary;
- }
-
- // Check to see if we should resolve based on our contents
- if (args.IsDirectory && !ShouldResolvePathContents(args))
- {
- return null;
- }
-
- return ResolveItem(args, resolvers);
- }
-
- private readonly List<string> _ignoredPaths = new List<string>();
-
- public void RegisterIgnoredPath(string path)
- {
- lock (_ignoredPaths)
- {
- _ignoredPaths.Add(path);
- }
- }
- public void UnRegisterIgnoredPath(string path)
- {
- lock (_ignoredPaths)
- {
- _ignoredPaths.Remove(path);
- }
- }
-
- public bool IgnoreFile(FileSystemMetadata file, BaseItem parent)
- {
- if (EntityResolutionIgnoreRules.Any(r => r.ShouldIgnore(file, parent)))
- {
- return true;
- }
-
- //lock (_ignoredPaths)
- {
- if (_ignoredPaths.Contains(file.FullName, StringComparer.OrdinalIgnoreCase))
- {
- return true;
- }
- }
- return false;
- }
-
- public IEnumerable<FileSystemMetadata> NormalizeRootPathList(IEnumerable<FileSystemMetadata> paths)
- {
- var originalList = paths.ToList();
-
- var list = originalList.Where(i => i.IsDirectory)
- .Select(i => _fileSystem.NormalizePath(i.FullName))
- .Distinct(StringComparer.OrdinalIgnoreCase)
- .ToList();
-
- var dupes = list.Where(subPath => !subPath.EndsWith(":\\", StringComparison.OrdinalIgnoreCase) && list.Any(i => _fileSystem.ContainsSubPath(i, subPath)))
- .ToList();
-
- foreach (var dupe in dupes)
- {
- _logger.Info("Found duplicate path: {0}", dupe);
- }
-
- var newList = list.Except(dupes, StringComparer.OrdinalIgnoreCase).Select(_fileSystem.GetDirectoryInfo).ToList();
- newList.AddRange(originalList.Where(i => !i.IsDirectory));
- return newList;
- }
-
- /// <summary>
- /// Determines whether a path should be ignored based on its contents - called after the contents have been read
- /// </summary>
- /// <param name="args">The args.</param>
- /// <returns><c>true</c> if XXXX, <c>false</c> otherwise</returns>
- private static bool ShouldResolvePathContents(ItemResolveArgs args)
- {
- // Ignore any folders containing a file called .ignore
- return !args.ContainsFileSystemEntryByName(".ignore");
- }
-
- public IEnumerable<BaseItem> ResolvePaths(IEnumerable<FileSystemMetadata> files, IDirectoryService directoryService, Folder parent, LibraryOptions libraryOptions, string collectionType)
- {
- return ResolvePaths(files, directoryService, parent, libraryOptions, collectionType, EntityResolvers);
- }
-
- public IEnumerable<BaseItem> ResolvePaths(IEnumerable<FileSystemMetadata> files,
- IDirectoryService directoryService,
- Folder parent,
- LibraryOptions libraryOptions,
- string collectionType,
- IItemResolver[] resolvers)
- {
- var fileList = files.Where(i => !IgnoreFile(i, parent)).ToList();
-
- if (parent != null)
- {
- var multiItemResolvers = resolvers == null ? MultiItemResolvers : resolvers.OfType<IMultiItemResolver>().ToArray();
-
- foreach (var resolver in multiItemResolvers)
- {
- var result = resolver.ResolveMultiple(parent, fileList, collectionType, directoryService);
-
- if (result != null && result.Items.Count > 0)
- {
- var items = new List<BaseItem>();
- items.AddRange(result.Items);
-
- foreach (var item in items)
- {
- ResolverHelper.SetInitialItemValues(item, parent, _fileSystem, this, directoryService);
- }
- items.AddRange(ResolveFileList(result.ExtraFiles, directoryService, parent, collectionType, resolvers, libraryOptions));
- return items;
- }
- }
- }
-
- return ResolveFileList(fileList, directoryService, parent, collectionType, resolvers, libraryOptions);
- }
-
- private IEnumerable<BaseItem> ResolveFileList(IEnumerable<FileSystemMetadata> fileList,
- IDirectoryService directoryService,
- Folder parent,
- string collectionType,
- IItemResolver[] resolvers,
- LibraryOptions libraryOptions)
- {
- return fileList.Select(f =>
- {
- try
- {
- return ResolvePath(f, directoryService, resolvers, parent, collectionType, libraryOptions);
- }
- catch (Exception ex)
- {
- _logger.ErrorException("Error resolving path {0}", ex, f.FullName);
- return null;
- }
- }).Where(i => i != null);
- }
-
- /// <summary>
- /// Creates the root media folder
- /// </summary>
- /// <returns>AggregateFolder.</returns>
- /// <exception cref="System.InvalidOperationException">Cannot create the root folder until plugins have loaded</exception>
- public AggregateFolder CreateRootFolder()
- {
- var rootFolderPath = ConfigurationManager.ApplicationPaths.RootFolderPath;
-
- _fileSystem.CreateDirectory(rootFolderPath);
-
- var rootFolder = GetItemById(GetNewItemId(rootFolderPath, typeof(AggregateFolder))) as AggregateFolder ?? (AggregateFolder)ResolvePath(_fileSystem.GetDirectoryInfo(rootFolderPath));
-
- // Add in the plug-in folders
- foreach (var child in PluginFolderCreators)
- {
- var folder = child.GetFolder();
-
- if (folder != null)
- {
- 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());
- }
- }
-
- var dbItem = GetItemById(folder.Id) as BasePluginFolder;
-
- if (dbItem != null && string.Equals(dbItem.Path, folder.Path, StringComparison.OrdinalIgnoreCase))
- {
- folder = dbItem;
- }
-
- if (folder.ParentId != rootFolder.Id)
- {
- folder.ParentId = rootFolder.Id;
- var task = folder.UpdateToRepository(ItemUpdateType.MetadataImport, CancellationToken.None);
- Task.WaitAll(task);
- }
-
- rootFolder.AddVirtualChild(folder);
-
- RegisterItem(folder);
- }
- }
-
- return rootFolder;
- }
-
- private volatile UserRootFolder _userRootFolder;
- private readonly object _syncLock = new object();
- public Folder GetUserRootFolder()
- {
- if (_userRootFolder == null)
- {
- lock (_syncLock)
- {
- if (_userRootFolder == null)
- {
- var userRootPath = ConfigurationManager.ApplicationPaths.DefaultUserViewsPath;
-
- _fileSystem.CreateDirectory(userRootPath);
-
- var tmpItem = GetItemById(GetNewItemId(userRootPath, typeof(UserRootFolder))) as UserRootFolder;
-
- if (tmpItem == null)
- {
- tmpItem = (UserRootFolder)ResolvePath(_fileSystem.GetDirectoryInfo(userRootPath));
- }
-
- _userRootFolder = tmpItem;
- }
- }
- }
-
- return _userRootFolder;
- }
-
- public BaseItem FindByPath(string path, bool? isFolder)
- {
- // 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
-
- var query = new InternalItemsQuery
- {
- Path = path,
- IsFolder = isFolder,
- SortBy = new[] { ItemSortBy.DateCreated },
- SortOrder = SortOrder.Descending,
- Limit = 1
- };
-
- return GetItemList(query)
- .FirstOrDefault();
- }
-
- /// <summary>
- /// Gets a Person
- /// </summary>
- /// <param name="name">The name.</param>
- /// <returns>Task{Person}.</returns>
- public Person GetPerson(string name)
- {
- return CreateItemByName<Person>(Person.GetPath(name), name);
- }
-
- /// <summary>
- /// Gets a Studio
- /// </summary>
- /// <param name="name">The name.</param>
- /// <returns>Task{Studio}.</returns>
- public Studio GetStudio(string name)
- {
- return CreateItemByName<Studio>(Studio.GetPath(name), name);
- }
-
- /// <summary>
- /// Gets a Genre
- /// </summary>
- /// <param name="name">The name.</param>
- /// <returns>Task{Genre}.</returns>
- public Genre GetGenre(string name)
- {
- return CreateItemByName<Genre>(Genre.GetPath(name), name);
- }
-
- /// <summary>
- /// Gets the genre.
- /// </summary>
- /// <param name="name">The name.</param>
- /// <returns>Task{MusicGenre}.</returns>
- public MusicGenre GetMusicGenre(string name)
- {
- return CreateItemByName<MusicGenre>(MusicGenre.GetPath(name), name);
- }
-
- /// <summary>
- /// Gets the game genre.
- /// </summary>
- /// <param name="name">The name.</param>
- /// <returns>Task{GameGenre}.</returns>
- public GameGenre GetGameGenre(string name)
- {
- return CreateItemByName<GameGenre>(GameGenre.GetPath(name), name);
- }
-
- /// <summary>
- /// Gets a Year
- /// </summary>
- /// <param name="value">The value.</param>
- /// <returns>Task{Year}.</returns>
- /// <exception cref="System.ArgumentOutOfRangeException"></exception>
- public Year GetYear(int value)
- {
- if (value <= 0)
- {
- throw new ArgumentOutOfRangeException("Years less than or equal to 0 are invalid.");
- }
-
- var name = value.ToString(CultureInfo.InvariantCulture);
-
- return CreateItemByName<Year>(Year.GetPath(name), name);
- }
-
- /// <summary>
- /// Gets a Genre
- /// </summary>
- /// <param name="name">The name.</param>
- /// <returns>Task{Genre}.</returns>
- public MusicArtist GetArtist(string name)
- {
- return CreateItemByName<MusicArtist>(MusicArtist.GetPath(name), name);
- }
-
- private T CreateItemByName<T>(string path, string name)
- where T : BaseItem, new()
- {
- if (typeof(T) == typeof(MusicArtist))
- {
- var existing = GetItemList(new InternalItemsQuery
- {
- IncludeItemTypes = new[] { typeof(T).Name },
- Name = name
-
- }).Cast<MusicArtist>()
- .OrderBy(i => i.IsAccessedByName ? 1 : 0)
- .Cast<T>()
- .FirstOrDefault();
-
- if (existing != null)
- {
- return existing;
- }
- }
-
- var id = GetNewItemId(path, typeof(T));
-
- var item = GetItemById(id) as T;
-
- if (item == null)
- {
- item = new T
- {
- Name = name,
- Id = id,
- DateCreated = DateTime.UtcNow,
- DateModified = DateTime.UtcNow,
- Path = path
- };
-
- var task = CreateItem(item, CancellationToken.None);
- Task.WaitAll(task);
- }
-
- return item;
- }
-
- public IEnumerable<MusicArtist> GetAlbumArtists(IEnumerable<IHasAlbumArtist> items)
- {
- var names = items
- .SelectMany(i => i.AlbumArtists)
- .DistinctNames()
- .Select(i =>
- {
- try
- {
- var artist = GetArtist(i);
-
- return artist;
- }
- catch
- {
- // Already logged at lower levels
- return null;
- }
- })
- .Where(i => i != null);
-
- return names;
- }
-
- public IEnumerable<MusicArtist> GetArtists(IEnumerable<IHasArtist> items)
- {
- var names = items
- .SelectMany(i => i.AllArtists)
- .DistinctNames()
- .Select(i =>
- {
- try
- {
- var artist = GetArtist(i);
-
- return artist;
- }
- catch
- {
- // Already logged at lower levels
- return null;
- }
- })
- .Where(i => i != null);
-
- return names;
- }
-
- /// <summary>
- /// Validate and refresh the People sub-set of the IBN.
- /// The items are stored in the db but not loaded into memory until actually requested by an operation.
- /// </summary>
- /// <param name="cancellationToken">The cancellation token.</param>
- /// <param name="progress">The progress.</param>
- /// <returns>Task.</returns>
- public Task ValidatePeople(CancellationToken cancellationToken, IProgress<double> progress)
- {
- // Ensure the location is available.
- _fileSystem.CreateDirectory(ConfigurationManager.ApplicationPaths.PeoplePath);
-
- return new PeopleValidator(this, _logger, ConfigurationManager, _fileSystem).ValidatePeople(cancellationToken, progress);
- }
-
- /// <summary>
- /// Reloads the root media folder
- /// </summary>
- /// <param name="progress">The progress.</param>
- /// <param name="cancellationToken">The cancellation token.</param>
- /// <returns>Task.</returns>
- public Task ValidateMediaLibrary(IProgress<double> progress, CancellationToken cancellationToken)
- {
- // Just run the scheduled task so that the user can see it
- _taskManager.CancelIfRunningAndQueue<RefreshMediaLibraryTask>();
-
- return Task.FromResult(true);
- }
-
- /// <summary>
- /// Queues the library scan.
- /// </summary>
- public void QueueLibraryScan()
- {
- // Just run the scheduled task so that the user can see it
- _taskManager.QueueScheduledTask<RefreshMediaLibraryTask>();
- }
-
- /// <summary>
- /// Validates the media library internal.
- /// </summary>
- /// <param name="progress">The progress.</param>
- /// <param name="cancellationToken">The cancellation token.</param>
- /// <returns>Task.</returns>
- public async Task ValidateMediaLibraryInternal(IProgress<double> progress, CancellationToken cancellationToken)
- {
- IsScanRunning = true;
- _libraryMonitorFactory().Stop();
-
- try
- {
- await PerformLibraryValidation(progress, cancellationToken).ConfigureAwait(false);
- }
- finally
- {
- _libraryMonitorFactory().Start();
- IsScanRunning = false;
- }
- }
-
- private async Task PerformLibraryValidation(IProgress<double> progress, CancellationToken cancellationToken)
- {
- _logger.Info("Validating media library");
-
- 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 Progress<double>(), cancellationToken, new MetadataRefreshOptions(_fileSystem), recursive: false);
-
- progress.Report(1);
-
- var userRoot = GetUserRootFolder();
-
- await userRoot.RefreshMetadata(cancellationToken).ConfigureAwait(false);
-
- await userRoot.ValidateChildren(new Progress<double>(), cancellationToken, new MetadataRefreshOptions(_fileSystem), recursive: false).ConfigureAwait(false);
- progress.Report(2);
-
- var innerProgress = new ActionableProgress<double>();
-
- innerProgress.RegisterAction(pct => progress.Report(2 + pct * .73));
-
- // Now validate the entire media library
- await RootFolder.ValidateChildren(innerProgress, cancellationToken, new MetadataRefreshOptions(_fileSystem), recursive: true).ConfigureAwait(false);
-
- progress.Report(75);
-
- innerProgress = new ActionableProgress<double>();
-
- innerProgress.RegisterAction(pct => progress.Report(75 + pct * .25));
-
- // Run post-scan tasks
- await RunPostScanTasks(innerProgress, cancellationToken).ConfigureAwait(false);
-
- progress.Report(100);
- }
-
- /// <summary>
- /// Runs the post scan tasks.
- /// </summary>
- /// <param name="progress">The progress.</param>
- /// <param name="cancellationToken">The cancellation token.</param>
- /// <returns>Task.</returns>
- private async Task RunPostScanTasks(IProgress<double> progress, CancellationToken cancellationToken)
- {
- var tasks = PostscanTasks.ToList();
-
- var numComplete = 0;
- var numTasks = tasks.Count;
-
- foreach (var task in tasks)
- {
- var innerProgress = new ActionableProgress<double>();
-
- // Prevent access to modified closure
- var currentNumComplete = numComplete;
-
- innerProgress.RegisterAction(pct =>
- {
- double innerPercent = currentNumComplete * 100 + pct;
- innerPercent /= numTasks;
- progress.Report(innerPercent);
- });
-
- _logger.Debug("Running post-scan task {0}", task.GetType().Name);
-
- try
- {
- await task.Run(innerProgress, cancellationToken).ConfigureAwait(false);
- }
- catch (OperationCanceledException)
- {
- _logger.Info("Post-scan task cancelled: {0}", task.GetType().Name);
- }
- catch (Exception ex)
- {
- _logger.ErrorException("Error running postscan task", ex);
- }
-
- numComplete++;
- double percent = numComplete;
- percent /= numTasks;
- progress.Report(percent * 100);
- }
-
- progress.Report(100);
- }
-
- /// <summary>
- /// Gets the default view.
- /// </summary>
- /// <returns>IEnumerable{VirtualFolderInfo}.</returns>
- public IEnumerable<VirtualFolderInfo> GetVirtualFolders()
- {
- return GetView(ConfigurationManager.ApplicationPaths.DefaultUserViewsPath);
- }
-
- /// <summary>
- /// Gets the view.
- /// </summary>
- /// <param name="path">The path.</param>
- /// <returns>IEnumerable{VirtualFolderInfo}.</returns>
- private IEnumerable<VirtualFolderInfo> GetView(string path)
- {
- var topLibraryFolders = GetUserRootFolder().Children.ToList();
-
- return _fileSystem.GetDirectoryPaths(path)
- .Select(dir => GetVirtualFolderInfo(dir, topLibraryFolders));
- }
-
- private VirtualFolderInfo GetVirtualFolderInfo(string dir, List<BaseItem> allCollectionFolders)
- {
- var info = new VirtualFolderInfo
- {
- Name = Path.GetFileName(dir),
-
- Locations = Directory.EnumerateFiles(dir, "*.mblink", SearchOption.TopDirectoryOnly)
- .Select(_fileSystem.ResolveShortcut)
- .OrderBy(i => i)
- .ToList(),
-
- CollectionType = GetCollectionType(dir)
- };
-
- var libraryFolder = allCollectionFolders.FirstOrDefault(i => string.Equals(i.Path, dir, StringComparison.OrdinalIgnoreCase));
-
- if (libraryFolder != null && libraryFolder.HasImage(ImageType.Primary))
- {
- info.PrimaryImageItemId = libraryFolder.Id.ToString("N");
- }
-
- if (libraryFolder != null)
- {
- info.ItemId = libraryFolder.Id.ToString("N");
- info.LibraryOptions = GetLibraryOptions(libraryFolder);
- }
-
- return info;
- }
-
- private string GetCollectionType(string path)
- {
- return _fileSystem.GetFiles(path, false)
- .Where(i => string.Equals(i.Extension, ".collection", StringComparison.OrdinalIgnoreCase))
- .Select(i => _fileSystem.GetFileNameWithoutExtension(i))
- .FirstOrDefault();
- }
-
- /// <summary>
- /// Gets the item by id.
- /// </summary>
- /// <param name="id">The id.</param>
- /// <returns>BaseItem.</returns>
- /// <exception cref="System.ArgumentNullException">id</exception>
- public BaseItem GetItemById(Guid id)
- {
- if (id == Guid.Empty)
- {
- throw new ArgumentNullException("id");
- }
-
- BaseItem item;
-
- if (LibraryItemsCache.TryGetValue(id, out item))
- {
- return item;
- }
-
- item = RetrieveItem(id);
-
- //_logger.Debug("GetitemById {0}", id);
-
- if (item != null)
- {
- RegisterItem(item);
- }
-
- return item;
- }
-
- public IEnumerable<BaseItem> GetItemList(InternalItemsQuery query)
- {
- if (query.Recursive && query.ParentId.HasValue)
- {
- var parent = GetItemById(query.ParentId.Value);
- if (parent != null)
- {
- SetTopParentIdsOrAncestors(query, new List<BaseItem> { parent });
- query.ParentId = null;
- }
- }
-
- if (query.User != null)
- {
- AddUserToQuery(query, query.User);
- }
-
- return ItemRepository.GetItemList(query);
- }
-
- public IEnumerable<BaseItem> GetItemList(InternalItemsQuery query, IEnumerable<string> parentIds)
- {
- var parents = parentIds.Select(i => GetItemById(new Guid(i))).Where(i => i != null).ToList();
-
- SetTopParentIdsOrAncestors(query, parents);
-
- if (query.AncestorIds.Length == 0 && query.TopParentIds.Length == 0)
- {
- if (query.User != null)
- {
- AddUserToQuery(query, query.User);
- }
- }
-
- return ItemRepository.GetItemList(query);
- }
-
- public QueryResult<BaseItem> QueryItems(InternalItemsQuery query)
- {
- if (query.User != null)
- {
- AddUserToQuery(query, query.User);
- }
-
- if (query.EnableTotalRecordCount)
- {
- return ItemRepository.GetItems(query);
- }
-
- return new QueryResult<BaseItem>
- {
- Items = ItemRepository.GetItemList(query).ToArray()
- };
- }
-
- public List<Guid> GetItemIds(InternalItemsQuery query)
- {
- if (query.User != null)
- {
- AddUserToQuery(query, query.User);
- }
-
- return ItemRepository.GetItemIdsList(query);
- }
-
- public QueryResult<Tuple<BaseItem, ItemCounts>> GetStudios(InternalItemsQuery query)
- {
- if (query.User != null)
- {
- AddUserToQuery(query, query.User);
- }
-
- SetTopParentOrAncestorIds(query);
- return ItemRepository.GetStudios(query);
- }
-
- public QueryResult<Tuple<BaseItem, ItemCounts>> GetGenres(InternalItemsQuery query)
- {
- if (query.User != null)
- {
- AddUserToQuery(query, query.User);
- }
-
- SetTopParentOrAncestorIds(query);
- return ItemRepository.GetGenres(query);
- }
-
- public QueryResult<Tuple<BaseItem, ItemCounts>> GetGameGenres(InternalItemsQuery query)
- {
- if (query.User != null)
- {
- AddUserToQuery(query, query.User);
- }
-
- SetTopParentOrAncestorIds(query);
- return ItemRepository.GetGameGenres(query);
- }
-
- public QueryResult<Tuple<BaseItem, ItemCounts>> GetMusicGenres(InternalItemsQuery query)
- {
- if (query.User != null)
- {
- AddUserToQuery(query, query.User);
- }
-
- SetTopParentOrAncestorIds(query);
- return ItemRepository.GetMusicGenres(query);
- }
-
- public QueryResult<Tuple<BaseItem, ItemCounts>> GetAllArtists(InternalItemsQuery query)
- {
- if (query.User != null)
- {
- AddUserToQuery(query, query.User);
- }
-
- SetTopParentOrAncestorIds(query);
- return ItemRepository.GetAllArtists(query);
- }
-
- public QueryResult<Tuple<BaseItem, ItemCounts>> GetArtists(InternalItemsQuery query)
- {
- if (query.User != null)
- {
- AddUserToQuery(query, query.User);
- }
-
- SetTopParentOrAncestorIds(query);
- return ItemRepository.GetArtists(query);
- }
-
- private void SetTopParentOrAncestorIds(InternalItemsQuery query)
- {
- if (query.AncestorIds.Length == 0)
- {
- return;
- }
-
- var parents = query.AncestorIds.Select(i => GetItemById(new Guid(i))).ToList();
-
- if (parents.All(i =>
- {
- if (i is ICollectionFolder || i is UserView)
- {
- return true;
- }
-
- //_logger.Debug("Query requires ancestor query due to type: " + i.GetType().Name);
- return false;
-
- }))
- {
- // Optimize by querying against top level views
- query.TopParentIds = parents.SelectMany(i => GetTopParentsForQuery(i, query.User)).Select(i => i.Id.ToString("N")).ToArray();
- query.AncestorIds = new string[] { };
- }
- }
-
- public QueryResult<Tuple<BaseItem, ItemCounts>> GetAlbumArtists(InternalItemsQuery query)
- {
- if (query.User != null)
- {
- AddUserToQuery(query, query.User);
- }
-
- SetTopParentOrAncestorIds(query);
- return ItemRepository.GetAlbumArtists(query);
- }
-
- public QueryResult<BaseItem> GetItemsResult(InternalItemsQuery query)
- {
- if (query.Recursive && query.ParentId.HasValue)
- {
- var parent = GetItemById(query.ParentId.Value);
- if (parent != null)
- {
- SetTopParentIdsOrAncestors(query, new List<BaseItem> { parent });
- query.ParentId = null;
- }
- }
-
- if (query.User != null)
- {
- AddUserToQuery(query, query.User);
- }
-
- if (query.EnableTotalRecordCount)
- {
- return ItemRepository.GetItems(query);
- }
-
- return new QueryResult<BaseItem>
- {
- Items = ItemRepository.GetItemList(query).ToArray()
- };
- }
-
- private void SetTopParentIdsOrAncestors(InternalItemsQuery query, List<BaseItem> parents)
- {
- if (parents.All(i =>
- {
- if (i is ICollectionFolder || i is UserView)
- {
- return true;
- }
-
- //_logger.Debug("Query requires ancestor query due to type: " + i.GetType().Name);
- return false;
-
- }))
- {
- // Optimize by querying against top level views
- query.TopParentIds = parents.SelectMany(i => GetTopParentsForQuery(i, query.User)).Select(i => i.Id.ToString("N")).ToArray();
- }
- 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();
- }
- }
-
- private void AddUserToQuery(InternalItemsQuery query, User user)
- {
- if (query.AncestorIds.Length == 0 &&
- !query.ParentId.HasValue &&
- query.ChannelIds.Length == 0 &&
- query.TopParentIds.Length == 0 &&
- string.IsNullOrWhiteSpace(query.AncestorWithPresentationUniqueKey)
- && query.ItemIds.Length == 0)
- {
- var userViews = _userviewManager().GetUserViews(new UserViewQuery
- {
- UserId = user.Id.ToString("N"),
- IncludeHidden = true
-
- }, CancellationToken.None).Result.ToList();
-
- query.TopParentIds = userViews.SelectMany(i => GetTopParentsForQuery(i, user)).Select(i => i.Id.ToString("N")).ToArray();
- }
- }
-
- private IEnumerable<BaseItem> GetTopParentsForQuery(BaseItem item, User user)
- {
- var view = item as UserView;
-
- if (view != null)
- {
- if (string.Equals(view.ViewType, CollectionType.LiveTv))
- {
- return new[] { view };
- }
- 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;
- }
-
- // Translate view into folders
- if (view.DisplayParentId != Guid.Empty)
- {
- var displayParent = GetItemById(view.DisplayParentId);
- if (displayParent != null)
- {
- return GetTopParentsForQuery(displayParent, user);
- }
- return new BaseItem[] { };
- }
- if (view.ParentId != Guid.Empty)
- {
- var displayParent = GetItemById(view.ParentId);
- if (displayParent != null)
- {
- return GetTopParentsForQuery(displayParent, user);
- }
- return new BaseItem[] { };
- }
-
- // Handle grouping
- if (user != null && !string.IsNullOrWhiteSpace(view.ViewType) && UserView.IsEligibleForGrouping(view.ViewType))
- {
- return user.RootFolder
- .GetChildren(user, true)
- .OfType<CollectionFolder>()
- .Where(i => string.IsNullOrWhiteSpace(i.CollectionType) || string.Equals(i.CollectionType, view.ViewType, StringComparison.OrdinalIgnoreCase))
- .Where(i => user.IsFolderGrouped(i.Id))
- .SelectMany(i => GetTopParentsForQuery(i, user));
- }
- return new BaseItem[] { };
- }
-
- var collectionFolder = item as CollectionFolder;
- if (collectionFolder != null)
- {
- return collectionFolder.GetPhysicalParents();
- }
-
- var topParent = item.GetTopParent();
- if (topParent != null)
- {
- return new[] { topParent };
- }
- return new BaseItem[] { };
- }
-
- /// <summary>
- /// Gets the intros.
- /// </summary>
- /// <param name="item">The item.</param>
- /// <param name="user">The user.</param>
- /// <returns>IEnumerable{System.String}.</returns>
- public async Task<IEnumerable<Video>> GetIntros(BaseItem item, User user)
- {
- var tasks = IntroProviders
- .OrderBy(i => i.GetType().Name.IndexOf("Default", StringComparison.OrdinalIgnoreCase) == -1 ? 0 : 1)
- .Take(1)
- .Select(i => GetIntros(i, item, user));
-
- var items = await Task.WhenAll(tasks).ConfigureAwait(false);
-
- return items
- .SelectMany(i => i.ToArray())
- .Select(ResolveIntro)
- .Where(i => i != null);
- }
-
- /// <summary>
- /// Gets the intros.
- /// </summary>
- /// <param name="provider">The provider.</param>
- /// <param name="item">The item.</param>
- /// <param name="user">The user.</param>
- /// <returns>Task&lt;IEnumerable&lt;IntroInfo&gt;&gt;.</returns>
- private async Task<IEnumerable<IntroInfo>> GetIntros(IIntroProvider provider, BaseItem item, User user)
- {
- try
- {
- return await provider.GetIntros(item, user).ConfigureAwait(false);
- }
- catch (Exception ex)
- {
- _logger.ErrorException("Error getting intros", ex);
-
- return new List<IntroInfo>();
- }
- }
-
- /// <summary>
- /// Gets all intro files.
- /// </summary>
- /// <returns>IEnumerable{System.String}.</returns>
- public IEnumerable<string> GetAllIntroFiles()
- {
- return IntroProviders.SelectMany(i =>
- {
- try
- {
- return i.GetAllIntroFiles().ToList();
- }
- catch (Exception ex)
- {
- _logger.ErrorException("Error getting intro files", ex);
-
- return new List<string>();
- }
- });
- }
-
- /// <summary>
- /// Resolves the intro.
- /// </summary>
- /// <param name="info">The info.</param>
- /// <returns>Video.</returns>
- private Video ResolveIntro(IntroInfo info)
- {
- Video video = null;
-
- if (info.ItemId.HasValue)
- {
- // Get an existing item by Id
- video = GetItemById(info.ItemId.Value) as Video;
-
- if (video == null)
- {
- _logger.Error("Unable to locate item with Id {0}.", info.ItemId.Value);
- }
- }
- else if (!string.IsNullOrEmpty(info.Path))
- {
- try
- {
- // Try to resolve the path into a video
- video = ResolvePath(_fileSystem.GetFileSystemInfo(info.Path)) as Video;
-
- if (video == null)
- {
- _logger.Error("Intro resolver returned null for {0}.", info.Path);
- }
- else
- {
- // Pull the saved db item that will include metadata
- var dbItem = GetItemById(video.Id) as Video;
-
- if (dbItem != null)
- {
- video = dbItem;
- }
- else
- {
- return null;
- }
- }
- }
- catch (Exception ex)
- {
- _logger.ErrorException("Error resolving path {0}.", ex, info.Path);
- }
- }
- else
- {
- _logger.Error("IntroProvider returned an IntroInfo with null Path and ItemId.");
- }
-
- return video;
- }
-
- /// <summary>
- /// Sorts the specified sort by.
- /// </summary>
- /// <param name="items">The items.</param>
- /// <param name="user">The user.</param>
- /// <param name="sortBy">The sort by.</param>
- /// <param name="sortOrder">The sort order.</param>
- /// <returns>IEnumerable{BaseItem}.</returns>
- public IEnumerable<BaseItem> Sort(IEnumerable<BaseItem> items, User user, IEnumerable<string> sortBy, SortOrder sortOrder)
- {
- var isFirst = true;
-
- IOrderedEnumerable<BaseItem> orderedItems = null;
-
- foreach (var orderBy in sortBy.Select(o => GetComparer(o, user)).Where(c => c != null))
- {
- if (isFirst)
- {
- orderedItems = sortOrder == SortOrder.Descending ? items.OrderByDescending(i => i, orderBy) : items.OrderBy(i => i, orderBy);
- }
- else
- {
- orderedItems = sortOrder == SortOrder.Descending ? orderedItems.ThenByDescending(i => i, orderBy) : orderedItems.ThenBy(i => i, orderBy);
- }
-
- isFirst = false;
- }
-
- return orderedItems ?? items;
- }
-
- /// <summary>
- /// Gets the comparer.
- /// </summary>
- /// <param name="name">The name.</param>
- /// <param name="user">The user.</param>
- /// <returns>IBaseItemComparer.</returns>
- private IBaseItemComparer GetComparer(string name, User user)
- {
- var comparer = Comparers.FirstOrDefault(c => string.Equals(name, c.Name, StringComparison.OrdinalIgnoreCase));
-
- if (comparer != null)
- {
- // If it requires a user, create a new one, and assign the user
- if (comparer is IUserBaseItemComparer)
- {
- var userComparer = (IUserBaseItemComparer)Activator.CreateInstance(comparer.GetType());
-
- userComparer.User = user;
- userComparer.UserManager = _userManager;
- userComparer.UserDataRepository = _userDataRepository;
-
- return userComparer;
- }
- }
-
- return comparer;
- }
-
- /// <summary>
- /// Creates the item.
- /// </summary>
- /// <param name="item">The item.</param>
- /// <param name="cancellationToken">The cancellation token.</param>
- /// <returns>Task.</returns>
- public Task CreateItem(BaseItem item, CancellationToken cancellationToken)
- {
- return CreateItems(new[] { item }, cancellationToken);
- }
-
- /// <summary>
- /// Creates the items.
- /// </summary>
- /// <param name="items">The items.</param>
- /// <param name="cancellationToken">The cancellation token.</param>
- /// <returns>Task.</returns>
- public async Task CreateItems(IEnumerable<BaseItem> items, CancellationToken cancellationToken)
- {
- var list = items.ToList();
-
- await ItemRepository.SaveItems(list, cancellationToken).ConfigureAwait(false);
-
- foreach (var item in list)
- {
- RegisterItem(item);
- }
-
- if (ItemAdded != null)
- {
- foreach (var item in list)
- {
- try
- {
- ItemAdded(this, new ItemChangeEventArgs { Item = item });
- }
- catch (Exception ex)
- {
- _logger.ErrorException("Error in ItemAdded 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 async Task UpdateItem(BaseItem item, ItemUpdateType updateReason, CancellationToken cancellationToken)
- {
- var locationType = item.LocationType;
- if (locationType != LocationType.Remote && locationType != LocationType.Virtual)
- {
- await _providerManagerFactory().SaveMetadata(item, updateReason).ConfigureAwait(false);
- }
-
- 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);
-
- await ItemRepository.SaveItem(item, cancellationToken).ConfigureAwait(false);
-
- RegisterItem(item);
-
- if (ItemUpdated != null)
- {
- try
- {
- ItemUpdated(this, new ItemChangeEventArgs
- {
- Item = item,
- UpdateReason = updateReason
- });
- }
- catch (Exception ex)
- {
- _logger.ErrorException("Error in ItemUpdated event handler", ex);
- }
- }
- }
-
- /// <summary>
- /// Reports the item removed.
- /// </summary>
- /// <param name="item">The item.</param>
- public void ReportItemRemoved(BaseItem item)
- {
- if (ItemRemoved != null)
- {
- try
- {
- ItemRemoved(this, new ItemChangeEventArgs { Item = item });
- }
- catch (Exception ex)
- {
- _logger.ErrorException("Error in ItemRemoved event handler", ex);
- }
- }
- }
-
- /// <summary>
- /// Retrieves the item.
- /// </summary>
- /// <param name="id">The id.</param>
- /// <returns>BaseItem.</returns>
- public BaseItem RetrieveItem(Guid id)
- {
- return ItemRepository.RetrieveItem(id);
- }
-
- public IEnumerable<Folder> GetCollectionFolders(BaseItem item)
- {
- while (!(item.GetParent() is AggregateFolder) && item.GetParent() != null)
- {
- item = item.GetParent();
- }
-
- if (item == null)
- {
- return new List<Folder>();
- }
-
- return GetUserRootFolder().Children
- .OfType<Folder>()
- .Where(i => string.Equals(i.Path, item.Path, StringComparison.OrdinalIgnoreCase) || i.PhysicalLocations.Contains(item.Path, StringComparer.OrdinalIgnoreCase));
- }
-
- public LibraryOptions GetLibraryOptions(BaseItem item)
- {
- var collectionFolder = item as CollectionFolder;
- if (collectionFolder == null)
- {
- collectionFolder = GetCollectionFolders(item)
- .OfType<CollectionFolder>()
- .FirstOrDefault();
- }
-
- var options = collectionFolder == null ? new LibraryOptions() : collectionFolder.GetLibraryOptions();
-
- if (options.SchemaVersion < 3)
- {
- options.SaveLocalMetadata = ConfigurationManager.Configuration.SaveLocalMeta;
- options.EnableInternetProviders = ConfigurationManager.Configuration.EnableInternetProviders;
- }
-
- if (options.SchemaVersion < 2)
- {
- var chapterOptions = ConfigurationManager.GetConfiguration<ChapterOptions>("chapters");
- options.ExtractChapterImagesDuringLibraryScan = chapterOptions.ExtractDuringLibraryScan;
-
- if (collectionFolder != null)
- {
- if (string.Equals(collectionFolder.CollectionType, "movies", StringComparison.OrdinalIgnoreCase))
- {
- options.EnableChapterImageExtraction = chapterOptions.EnableMovieChapterImageExtraction;
- }
- else if (string.Equals(collectionFolder.CollectionType, CollectionType.TvShows, StringComparison.OrdinalIgnoreCase))
- {
- options.EnableChapterImageExtraction = chapterOptions.EnableEpisodeChapterImageExtraction;
- }
- }
- }
-
- return options;
- }
-
- public string GetContentType(BaseItem item)
- {
- string configuredContentType = GetConfiguredContentType(item, false);
- if (!string.IsNullOrWhiteSpace(configuredContentType))
- {
- return configuredContentType;
- }
- configuredContentType = GetConfiguredContentType(item, true);
- if (!string.IsNullOrWhiteSpace(configuredContentType))
- {
- return configuredContentType;
- }
- return GetInheritedContentType(item);
- }
-
- public string GetInheritedContentType(BaseItem item)
- {
- var type = GetTopFolderContentType(item);
-
- if (!string.IsNullOrWhiteSpace(type))
- {
- return type;
- }
-
- return item.GetParents()
- .Select(GetConfiguredContentType)
- .LastOrDefault(i => !string.IsNullOrWhiteSpace(i));
- }
-
- public string GetConfiguredContentType(BaseItem item)
- {
- return GetConfiguredContentType(item, false);
- }
-
- public string GetConfiguredContentType(string path)
- {
- return GetContentTypeOverride(path, false);
- }
-
- public string GetConfiguredContentType(BaseItem item, bool inheritConfiguredPath)
- {
- ICollectionFolder collectionFolder = item as ICollectionFolder;
- if (collectionFolder != null)
- {
- return collectionFolder.CollectionType;
- }
- return GetContentTypeOverride(item.ContainingFolderPath, inheritConfiguredPath);
- }
-
- private string GetContentTypeOverride(string path, bool inherit)
- {
- var nameValuePair = ConfigurationManager.Configuration.ContentTypes.FirstOrDefault(i => string.Equals(i.Name, path, StringComparison.OrdinalIgnoreCase) || (inherit && !string.IsNullOrWhiteSpace(i.Name) && _fileSystem.ContainsSubPath(i.Name, path)));
- if (nameValuePair != null)
- {
- return nameValuePair.Value;
- }
- return null;
- }
-
- private string GetTopFolderContentType(BaseItem item)
- {
- if (item == null)
- {
- return null;
- }
-
- while (!(item.GetParent() is AggregateFolder) && item.GetParent() != null)
- {
- item = item.GetParent();
- }
-
- 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));
- }
-
- private readonly TimeSpan _viewRefreshInterval = TimeSpan.FromHours(24);
- //private readonly TimeSpan _viewRefreshInterval = TimeSpan.FromMinutes(1);
-
- public Task<UserView> GetNamedView(User user,
- string name,
- string viewType,
- string sortName,
- CancellationToken cancellationToken)
- {
- return GetNamedView(user, name, null, viewType, sortName, cancellationToken);
- }
-
- public async Task<UserView> GetNamedView(string name,
- string viewType,
- string sortName,
- CancellationToken cancellationToken)
- {
- var path = Path.Combine(ConfigurationManager.ApplicationPaths.ItemsByNamePath, "views");
-
- path = Path.Combine(path, _fileSystem.GetValidFilename(viewType));
-
- var id = GetNewItemId(path + "_namedview_" + name, typeof(UserView));
-
- var item = GetItemById(id) as UserView;
-
- var refresh = false;
-
- if (item == null || !string.Equals(item.Path, path, StringComparison.OrdinalIgnoreCase))
- {
- _fileSystem.CreateDirectory(path);
-
- item = new UserView
- {
- Path = path,
- Id = id,
- DateCreated = DateTime.UtcNow,
- Name = name,
- ViewType = viewType,
- ForcedSortName = sortName
- };
-
- await CreateItem(item, cancellationToken).ConfigureAwait(false);
-
- 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)
- {
- await item.UpdateToRepository(ItemUpdateType.MetadataImport, CancellationToken.None).ConfigureAwait(false);
- _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
- });
- }
-
- return item;
- }
-
- public async Task<UserView> GetNamedView(User user,
- string name,
- string parentId,
- string viewType,
- string sortName,
- CancellationToken cancellationToken)
- {
- var idValues = "38_namedview_" + name + user.Id.ToString("N") + (parentId ?? string.Empty) + (viewType ?? string.Empty);
-
- var id = GetNewItemId(idValues, typeof(UserView));
-
- var path = Path.Combine(ConfigurationManager.ApplicationPaths.InternalMetadataPath, "views", id.ToString("N"));
-
- var item = GetItemById(id) as UserView;
-
- var isNew = false;
-
- if (item == null)
- {
- _fileSystem.CreateDirectory(path);
-
- item = new UserView
- {
- Path = path,
- Id = id,
- DateCreated = DateTime.UtcNow,
- Name = name,
- ViewType = viewType,
- ForcedSortName = sortName,
- UserId = user.Id
- };
-
- if (!string.IsNullOrWhiteSpace(parentId))
- {
- item.DisplayParentId = new Guid(parentId);
- }
-
- await CreateItem(item, cancellationToken).ConfigureAwait(false);
-
- isNew = true;
- }
-
- var refresh = isNew || 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)
- {
- _providerManagerFactory().QueueRefresh(item.Id, new MetadataRefreshOptions(_fileSystem)
- {
- // Need to force save to increment DateLastSaved
- ForceSave = true
- });
- }
-
- return item;
- }
-
- public async Task<UserView> GetShadowView(BaseItem parent,
- string viewType,
- string sortName,
- CancellationToken cancellationToken)
- {
- if (parent == null)
- {
- throw new ArgumentNullException("parent");
- }
-
- var name = parent.Name;
- var parentId = parent.Id;
-
- var idValues = "38_namedview_" + name + parentId + (viewType ?? string.Empty);
-
- var id = GetNewItemId(idValues, typeof(UserView));
-
- var path = parent.Path;
-
- var item = GetItemById(id) as UserView;
-
- var isNew = false;
-
- if (item == null)
- {
- _fileSystem.CreateDirectory(path);
-
- item = new UserView
- {
- Path = path,
- Id = id,
- DateCreated = DateTime.UtcNow,
- Name = name,
- ViewType = viewType,
- ForcedSortName = sortName
- };
-
- item.DisplayParentId = parentId;
-
- await CreateItem(item, cancellationToken).ConfigureAwait(false);
-
- isNew = true;
- }
-
- var refresh = isNew || 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)
- {
- _providerManagerFactory().QueueRefresh(item.Id, new MetadataRefreshOptions(_fileSystem)
- {
- // Need to force save to increment DateLastSaved
- ForceSave = true
- });
- }
-
- return item;
- }
-
- public async Task<UserView> GetNamedView(string name,
- string parentId,
- string viewType,
- string sortName,
- string uniqueId,
- CancellationToken cancellationToken)
- {
- if (string.IsNullOrWhiteSpace(name))
- {
- throw new ArgumentNullException("name");
- }
-
- var idValues = "37_namedview_" + name + (parentId ?? string.Empty) + (viewType ?? string.Empty);
- if (!string.IsNullOrWhiteSpace(uniqueId))
- {
- idValues += uniqueId;
- }
-
- var id = GetNewItemId(idValues, typeof(UserView));
-
- var path = Path.Combine(ConfigurationManager.ApplicationPaths.InternalMetadataPath, "views", id.ToString("N"));
-
- var item = GetItemById(id) as UserView;
-
- var isNew = false;
-
- if (item == null)
- {
- _fileSystem.CreateDirectory(path);
-
- item = new UserView
- {
- Path = path,
- Id = id,
- DateCreated = DateTime.UtcNow,
- Name = name,
- ViewType = viewType,
- ForcedSortName = sortName
- };
-
- if (!string.IsNullOrWhiteSpace(parentId))
- {
- item.DisplayParentId = new Guid(parentId);
- }
-
- await CreateItem(item, cancellationToken).ConfigureAwait(false);
-
- isNew = true;
- }
-
- if (!string.Equals(viewType, item.ViewType, StringComparison.OrdinalIgnoreCase))
- {
- item.ViewType = viewType;
- await item.UpdateToRepository(ItemUpdateType.MetadataEdit, cancellationToken).ConfigureAwait(false);
- }
-
- var refresh = isNew || 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)
- {
- _providerManagerFactory().QueueRefresh(item.Id, new MetadataRefreshOptions(_fileSystem)
- {
- // Need to force save to increment DateLastSaved
- ForceSave = true
- });
- }
-
- return item;
- }
-
- public bool IsVideoFile(string path, LibraryOptions libraryOptions)
- {
- var resolver = new VideoResolver(GetNamingOptions(libraryOptions), new PatternsLogger());
- return resolver.IsVideoFile(path);
- }
-
- public bool IsVideoFile(string path)
- {
- return IsVideoFile(path, new LibraryOptions());
- }
-
- public bool IsAudioFile(string path, LibraryOptions libraryOptions)
- {
- var parser = new AudioFileParser(GetNamingOptions(libraryOptions));
- return parser.IsAudioFile(path);
- }
-
- public bool IsAudioFile(string path)
- {
- return IsAudioFile(path, new LibraryOptions());
- }
-
- public int? GetSeasonNumberFromPath(string path)
- {
- return new SeasonPathParser(GetNamingOptions(), new RegexProvider()).Parse(path, true, true).SeasonNumber;
- }
-
- public bool FillMissingEpisodeNumbersFromPath(Episode episode)
- {
- var resolver = new EpisodeResolver(GetNamingOptions(),
- new PatternsLogger());
-
- var isFolder = episode.VideoType == VideoType.BluRay || episode.VideoType == VideoType.Dvd ||
- episode.VideoType == VideoType.HdDvd;
-
- var locationType = episode.LocationType;
-
- var episodeInfo = locationType == LocationType.FileSystem || locationType == LocationType.Offline ?
- resolver.Resolve(episode.Path, isFolder) :
- new Naming.TV.EpisodeInfo();
-
- if (episodeInfo == null)
- {
- episodeInfo = new Naming.TV.EpisodeInfo();
- }
-
- var changed = false;
-
- if (episodeInfo.IsByDate)
- {
- if (episode.IndexNumber.HasValue)
- {
- episode.IndexNumber = null;
- changed = true;
- }
-
- if (episode.IndexNumberEnd.HasValue)
- {
- episode.IndexNumberEnd = null;
- changed = true;
- }
-
- if (!episode.PremiereDate.HasValue)
- {
- if (episodeInfo.Year.HasValue && episodeInfo.Month.HasValue && episodeInfo.Day.HasValue)
- {
- episode.PremiereDate = new DateTime(episodeInfo.Year.Value, episodeInfo.Month.Value, episodeInfo.Day.Value).ToUniversalTime();
- }
-
- if (episode.PremiereDate.HasValue)
- {
- changed = true;
- }
- }
-
- if (!episode.ProductionYear.HasValue)
- {
- episode.ProductionYear = episodeInfo.Year;
-
- if (episode.ProductionYear.HasValue)
- {
- 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)
- {
- episode.IndexNumber = episodeInfo.EpisodeNumber;
-
- if (episode.IndexNumber.HasValue)
- {
- changed = true;
- }
- }
-
- if (!episode.IndexNumberEnd.HasValue)
- {
- episode.IndexNumberEnd = episodeInfo.EndingEpsiodeNumber;
-
- if (episode.IndexNumberEnd.HasValue)
- {
- changed = true;
- }
- }
-
- if (!episode.ParentIndexNumber.HasValue)
- {
- episode.ParentIndexNumber = episodeInfo.SeasonNumber;
-
- if (!episode.ParentIndexNumber.HasValue)
- {
- var season = episode.Season;
-
- if (season != null)
- {
- episode.ParentIndexNumber = season.IndexNumber;
- }
- }
-
- if (episode.ParentIndexNumber.HasValue)
- {
- changed = true;
- }
- }
- }
-
- return changed;
- }
-
- public NamingOptions GetNamingOptions()
- {
- return GetNamingOptions(new LibraryOptions());
- }
-
- public NamingOptions GetNamingOptions(LibraryOptions libraryOptions)
- {
- var options = new ExtendedNamingOptions();
-
- // 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");
- }
-
- return options;
- }
-
- public ItemLookupInfo ParseName(string name)
- {
- var resolver = new VideoResolver(GetNamingOptions(), new PatternsLogger());
-
- var result = resolver.CleanDateTime(name);
- var cleanName = resolver.CleanString(result.Name);
-
- return new ItemLookupInfo
- {
- Name = cleanName.Name,
- Year = result.Year
- };
- }
-
- public IEnumerable<Video> FindTrailers(BaseItem owner, List<FileSystemMetadata> fileSystemChildren, IDirectoryService directoryService)
- {
- var files = owner.DetectIsInMixedFolder() ? new List<FileSystemMetadata>() : fileSystemChildren.Where(i => i.IsDirectory)
- .Where(i => string.Equals(i.Name, BaseItem.TrailerFolderName, StringComparison.OrdinalIgnoreCase))
- .SelectMany(i => _fileSystem.GetFiles(i.FullName, false))
- .ToList();
-
- var videoListResolver = new VideoListResolver(GetNamingOptions(), new PatternsLogger());
-
- var videos = videoListResolver.Resolve(fileSystemChildren);
-
- var currentVideo = videos.FirstOrDefault(i => string.Equals(owner.Path, i.Files.First().Path, StringComparison.OrdinalIgnoreCase));
-
- if (currentVideo != null)
- {
- files.AddRange(currentVideo.Extras.Where(i => string.Equals(i.ExtraType, "trailer", StringComparison.OrdinalIgnoreCase)).Select(i => _fileSystem.GetFileInfo(i.Path)));
- }
-
- var resolvers = new IItemResolver[]
- {
- new GenericVideoResolver<Trailer>(this)
- };
-
- return ResolvePaths(files, directoryService, null, new LibraryOptions(), null, resolvers)
- .OfType<Trailer>()
- .Select(video =>
- {
- // Try to retrieve it from the db. If we don't find it, use the resolved version
- var dbItem = GetItemById(video.Id) as Trailer;
-
- if (dbItem != null)
- {
- video = dbItem;
- }
-
- video.ExtraType = ExtraType.Trailer;
- video.TrailerTypes = new List<TrailerType> { TrailerType.LocalTrailer };
-
- return video;
-
- // Sort them so that the list can be easily compared for changes
- }).OrderBy(i => i.Path).ToList();
- }
-
- public IEnumerable<Video> FindExtras(BaseItem owner, List<FileSystemMetadata> fileSystemChildren, IDirectoryService directoryService)
- {
- var files = fileSystemChildren.Where(i => i.IsDirectory)
- .Where(i => string.Equals(i.Name, "extras", StringComparison.OrdinalIgnoreCase) || string.Equals(i.Name, "specials", StringComparison.OrdinalIgnoreCase))
- .SelectMany(i => _fileSystem.GetFiles(i.FullName, false))
- .ToList();
-
- var videoListResolver = new VideoListResolver(GetNamingOptions(), new PatternsLogger());
-
- var videos = videoListResolver.Resolve(fileSystemChildren);
-
- var currentVideo = videos.FirstOrDefault(i => string.Equals(owner.Path, i.Files.First().Path, StringComparison.OrdinalIgnoreCase));
-
- if (currentVideo != null)
- {
- files.AddRange(currentVideo.Extras.Where(i => !string.Equals(i.ExtraType, "trailer", StringComparison.OrdinalIgnoreCase)).Select(i => _fileSystem.GetFileInfo(i.Path)));
- }
-
- return ResolvePaths(files, directoryService, null, new LibraryOptions(), null)
- .OfType<Video>()
- .Select(video =>
- {
- // Try to retrieve it from the db. If we don't find it, use the resolved version
- var dbItem = GetItemById(video.Id) as Video;
-
- if (dbItem != null)
- {
- video = dbItem;
- }
-
- SetExtraTypeFromFilename(video);
-
- return video;
-
- // Sort them so that the list can be easily compared for changes
- }).OrderBy(i => i.Path).ToList();
- }
-
- public string GetPathAfterNetworkSubstitution(string path, BaseItem ownerItem)
- {
- if (ownerItem != null)
- {
- var libraryOptions = GetLibraryOptions(ownerItem);
- if (libraryOptions != null)
- {
- foreach (var pathInfo in libraryOptions.PathInfos)
- {
- if (string.IsNullOrWhiteSpace(pathInfo.NetworkPath))
- {
- continue;
- }
-
- var substitutionResult = SubstitutePathInternal(path, pathInfo.Path, pathInfo.NetworkPath);
- if (substitutionResult.Item2)
- {
- return substitutionResult.Item1;
- }
- }
- }
- }
-
- var metadataPath = ConfigurationManager.Configuration.MetadataPath;
- var metadataNetworkPath = ConfigurationManager.Configuration.MetadataNetworkPath;
-
- if (!string.IsNullOrWhiteSpace(metadataPath) && !string.IsNullOrWhiteSpace(metadataNetworkPath))
- {
- var metadataSubstitutionResult = SubstitutePathInternal(path, metadataPath, metadataNetworkPath);
- if (metadataSubstitutionResult.Item2)
- {
- return metadataSubstitutionResult.Item1;
- }
- }
-
- foreach (var map in ConfigurationManager.Configuration.PathSubstitutions)
- {
- var substitutionResult = SubstitutePathInternal(path, map.From, map.To);
- if (substitutionResult.Item2)
- {
- return substitutionResult.Item1;
- }
- }
-
- return path;
- }
-
- public string SubstitutePath(string path, string from, string to)
- {
- return SubstitutePathInternal(path, from, to).Item1;
- }
-
- private Tuple<string, bool> SubstitutePathInternal(string path, string from, string to)
- {
- if (string.IsNullOrWhiteSpace(path))
- {
- throw new ArgumentNullException("path");
- }
- if (string.IsNullOrWhiteSpace(from))
- {
- throw new ArgumentNullException("from");
- }
- if (string.IsNullOrWhiteSpace(to))
- {
- throw new ArgumentNullException("to");
- }
-
- from = from.Trim();
- to = to.Trim();
-
- var newPath = path.Replace(from, to, StringComparison.OrdinalIgnoreCase);
- var changed = false;
-
- if (!string.Equals(newPath, path))
- {
- if (to.IndexOf('/') != -1)
- {
- newPath = newPath.Replace('\\', '/');
- }
- else
- {
- newPath = newPath.Replace('/', '\\');
- }
-
- changed = true;
- }
-
- return new Tuple<string, bool>(newPath, changed);
- }
-
- private void SetExtraTypeFromFilename(Video item)
- {
- var resolver = new ExtraResolver(GetNamingOptions(), new PatternsLogger(), new RegexProvider());
-
- var result = resolver.GetExtraInfo(item.Path);
-
- if (string.Equals(result.ExtraType, "deletedscene", StringComparison.OrdinalIgnoreCase))
- {
- item.ExtraType = ExtraType.DeletedScene;
- }
- else if (string.Equals(result.ExtraType, "behindthescenes", StringComparison.OrdinalIgnoreCase))
- {
- item.ExtraType = ExtraType.BehindTheScenes;
- }
- else if (string.Equals(result.ExtraType, "interview", StringComparison.OrdinalIgnoreCase))
- {
- item.ExtraType = ExtraType.Interview;
- }
- else if (string.Equals(result.ExtraType, "scene", StringComparison.OrdinalIgnoreCase))
- {
- item.ExtraType = ExtraType.Scene;
- }
- else if (string.Equals(result.ExtraType, "sample", StringComparison.OrdinalIgnoreCase))
- {
- item.ExtraType = ExtraType.Sample;
- }
- else
- {
- item.ExtraType = ExtraType.Clip;
- }
- }
-
- public List<PersonInfo> GetPeople(InternalPeopleQuery query)
- {
- return ItemRepository.GetPeople(query);
- }
-
- public List<PersonInfo> GetPeople(BaseItem item)
- {
- if (item.SupportsPeople)
- {
- var people = GetPeople(new InternalPeopleQuery
- {
- ItemId = item.Id
- });
-
- if (people.Count > 0)
- {
- return people;
- }
- }
-
- return new List<PersonInfo>();
- }
-
- public List<Person> GetPeopleItems(InternalPeopleQuery query)
- {
- return ItemRepository.GetPeopleNames(query).Select(i =>
- {
- try
- {
- return GetPerson(i);
- }
- catch (Exception ex)
- {
- _logger.ErrorException("Error getting person", ex);
- return null;
- }
-
- }).Where(i => i != null).ToList();
- }
-
- public List<string> GetPeopleNames(InternalPeopleQuery query)
- {
- return ItemRepository.GetPeopleNames(query);
- }
-
- public Task UpdatePeople(BaseItem item, List<PersonInfo> people)
- {
- if (!item.SupportsPeople)
- {
- return Task.FromResult(true);
- }
-
- return ItemRepository.UpdatePeople(item.Id, people);
- }
-
- private readonly SemaphoreSlim _dynamicImageResourcePool = new SemaphoreSlim(1, 1);
- public async Task<ItemImageInfo> ConvertImageToLocal(IHasImages item, ItemImageInfo image, int imageIndex)
- {
- foreach (var url in image.Path.Split('|'))
- {
- try
- {
- _logger.Debug("ConvertImageToLocal item {0} - image url: {1}", item.Id, url);
-
- await _providerManagerFactory().SaveImage(item, url, _dynamicImageResourcePool, image.Type, imageIndex, CancellationToken.None).ConfigureAwait(false);
-
- var newImage = item.GetImageInfo(image.Type, imageIndex);
-
- if (newImage != null)
- {
- newImage.IsPlaceholder = image.IsPlaceholder;
- }
-
- await item.UpdateToRepository(ItemUpdateType.ImageUpdate, CancellationToken.None).ConfigureAwait(false);
-
- return item.GetImageInfo(image.Type, imageIndex);
- }
- catch (HttpException ex)
- {
- if (ex.StatusCode.HasValue && ex.StatusCode.Value == HttpStatusCode.NotFound)
- {
- continue;
- }
- throw;
- }
- }
-
- // Remove this image to prevent it from retrying over and over
- item.RemoveImage(image);
- await item.UpdateToRepository(ItemUpdateType.ImageUpdate, CancellationToken.None).ConfigureAwait(false);
-
- throw new InvalidOperationException();
- }
-
- public void AddVirtualFolder(string name, string collectionType, LibraryOptions options, bool refreshLibrary)
- {
- if (string.IsNullOrWhiteSpace(name))
- {
- throw new ArgumentNullException("name");
- }
-
- name = _fileSystem.GetValidFilename(name);
-
- var rootFolderPath = ConfigurationManager.ApplicationPaths.DefaultUserViewsPath;
-
- var virtualFolderPath = Path.Combine(rootFolderPath, name);
- while (_fileSystem.DirectoryExists(virtualFolderPath))
- {
- name += "1";
- virtualFolderPath = Path.Combine(rootFolderPath, name);
- }
-
- var mediaPathInfos = options.PathInfos;
- if (mediaPathInfos != null)
- {
- var invalidpath = mediaPathInfos.FirstOrDefault(i => !_fileSystem.DirectoryExists(i.Path));
- if (invalidpath != null)
- {
- throw new ArgumentException("The specified path does not exist: " + invalidpath.Path + ".");
- }
- }
-
- _libraryMonitorFactory().Stop();
-
- try
- {
- _fileSystem.CreateDirectory(virtualFolderPath);
-
- if (!string.IsNullOrEmpty(collectionType))
- {
- var path = Path.Combine(virtualFolderPath, collectionType + ".collection");
-
- using (File.Create(path))
- {
-
- }
- }
-
- CollectionFolder.SaveLibraryOptions(virtualFolderPath, options);
-
- if (mediaPathInfos != null)
- {
- foreach (var path in mediaPathInfos)
- {
- AddMediaPathInternal(name, path, false);
- }
- }
- }
- finally
- {
- Task.Run(() =>
- {
- // No need to start if scanning the library because it will handle it
- if (refreshLibrary)
- {
- ValidateMediaLibrary(new Progress<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);
-
- _libraryMonitorFactory().Start();
- }
- });
- }
- }
-
- private bool ValidateNetworkPath(string path)
- {
- if (Environment.OSVersion.Platform == PlatformID.Win32NT)
- {
- // We can't validate protocol-based paths, so just allow them
- if (path.IndexOf("://", StringComparison.OrdinalIgnoreCase) == -1)
- {
- return Directory.Exists(path);
- }
- }
-
- // Without native support for unc, we cannot validate this when running under mono
- return true;
- }
-
- private const string ShortcutFileExtension = ".mblink";
- private const string ShortcutFileSearch = "*" + ShortcutFileExtension;
- public void AddMediaPath(string virtualFolderName, MediaPathInfo pathInfo)
- {
- AddMediaPathInternal(virtualFolderName, pathInfo, true);
- }
-
- private void AddMediaPathInternal(string virtualFolderName, MediaPathInfo pathInfo, bool saveLibraryOptions)
- {
- if (pathInfo == null)
- {
- throw new ArgumentNullException("path");
- }
-
- var path = pathInfo.Path;
-
- if (string.IsNullOrWhiteSpace(path))
- {
- throw new ArgumentNullException("path");
- }
-
- if (!_fileSystem.DirectoryExists(path))
- {
- throw new DirectoryNotFoundException("The path does not exist.");
- }
-
- if (!string.IsNullOrWhiteSpace(pathInfo.NetworkPath) && !ValidateNetworkPath(pathInfo.NetworkPath))
- {
- throw new DirectoryNotFoundException("The network path does not exist.");
- }
-
- var rootFolderPath = ConfigurationManager.ApplicationPaths.DefaultUserViewsPath;
- var virtualFolderPath = Path.Combine(rootFolderPath, virtualFolderName);
-
- var shortcutFilename = _fileSystem.GetFileNameWithoutExtension(path);
-
- var lnk = Path.Combine(virtualFolderPath, shortcutFilename + ShortcutFileExtension);
-
- while (_fileSystem.FileExists(lnk))
- {
- shortcutFilename += "1";
- lnk = Path.Combine(virtualFolderPath, shortcutFilename + ShortcutFileExtension);
- }
-
- _fileSystem.CreateShortcut(lnk, path);
-
- RemoveContentTypeOverrides(path);
-
- if (saveLibraryOptions)
- {
- var libraryOptions = CollectionFolder.GetLibraryOptions(virtualFolderPath);
-
- var list = libraryOptions.PathInfos.ToList();
- list.Add(pathInfo);
- libraryOptions.PathInfos = list.ToArray();
-
- SyncLibraryOptionsToLocations(virtualFolderPath, libraryOptions);
-
- CollectionFolder.SaveLibraryOptions(virtualFolderPath, libraryOptions);
- }
- }
-
- public void UpdateMediaPath(string virtualFolderName, MediaPathInfo pathInfo)
- {
- if (pathInfo == null)
- {
- throw new ArgumentNullException("path");
- }
-
- if (!string.IsNullOrWhiteSpace(pathInfo.NetworkPath) && !ValidateNetworkPath(pathInfo.NetworkPath))
- {
- throw new DirectoryNotFoundException("The network path does not exist.");
- }
-
- var rootFolderPath = ConfigurationManager.ApplicationPaths.DefaultUserViewsPath;
- var virtualFolderPath = Path.Combine(rootFolderPath, virtualFolderName);
-
- var libraryOptions = CollectionFolder.GetLibraryOptions(virtualFolderPath);
-
- SyncLibraryOptionsToLocations(virtualFolderPath, libraryOptions);
-
- var list = libraryOptions.PathInfos.ToList();
- foreach (var originalPathInfo in list)
- {
- if (string.Equals(pathInfo.Path, originalPathInfo.Path, StringComparison.Ordinal))
- {
- originalPathInfo.NetworkPath = pathInfo.NetworkPath;
- break;
- }
- }
-
- libraryOptions.PathInfos = list.ToArray();
-
- CollectionFolder.SaveLibraryOptions(virtualFolderPath, libraryOptions);
- }
-
- private void SyncLibraryOptionsToLocations(string virtualFolderPath, LibraryOptions options)
- {
- var topLibraryFolders = GetUserRootFolder().Children.ToList();
- var info = GetVirtualFolderInfo(virtualFolderPath, topLibraryFolders);
-
- if (info.Locations.Count > 0 && info.Locations.Count != options.PathInfos.Length)
- {
- var list = options.PathInfos.ToList();
-
- foreach (var location in info.Locations)
- {
- if (!list.Any(i => string.Equals(i.Path, location, StringComparison.Ordinal)))
- {
- list.Add(new MediaPathInfo
- {
- Path = location
- });
- }
- }
-
- options.PathInfos = list.ToArray();
- }
- }
-
- public void RemoveVirtualFolder(string name, bool refreshLibrary)
- {
- if (string.IsNullOrWhiteSpace(name))
- {
- throw new ArgumentNullException("name");
- }
-
- var rootFolderPath = ConfigurationManager.ApplicationPaths.DefaultUserViewsPath;
-
- var path = Path.Combine(rootFolderPath, name);
-
- if (!_fileSystem.DirectoryExists(path))
- {
- throw new DirectoryNotFoundException("The media folder does not exist");
- }
-
- _libraryMonitorFactory().Stop();
-
- try
- {
- _fileSystem.DeleteDirectory(path, true);
- }
- finally
- {
- Task.Run(() =>
- {
- // No need to start if scanning the library because it will handle it
- if (refreshLibrary)
- {
- ValidateMediaLibrary(new Progress<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);
-
- _libraryMonitorFactory().Start();
- }
- });
- }
- }
-
- private void RemoveContentTypeOverrides(string path)
- {
- if (string.IsNullOrWhiteSpace(path))
- {
- throw new ArgumentNullException("path");
- }
-
- var removeList = new List<NameValuePair>();
-
- foreach (var contentType in ConfigurationManager.Configuration.ContentTypes)
- {
- if (string.Equals(path, contentType.Name, StringComparison.OrdinalIgnoreCase)
- || _fileSystem.ContainsSubPath(path, contentType.Name))
- {
- removeList.Add(contentType);
- }
- }
-
- if (removeList.Count > 0)
- {
- ConfigurationManager.Configuration.ContentTypes = ConfigurationManager.Configuration.ContentTypes
- .Except(removeList)
- .ToArray();
-
- ConfigurationManager.SaveConfiguration();
- }
- }
-
- public void RemoveMediaPath(string virtualFolderName, string mediaPath)
- {
- if (string.IsNullOrWhiteSpace(mediaPath))
- {
- throw new ArgumentNullException("mediaPath");
- }
-
- var rootFolderPath = ConfigurationManager.ApplicationPaths.DefaultUserViewsPath;
- var virtualFolderPath = Path.Combine(rootFolderPath, virtualFolderName);
-
- if (!_fileSystem.DirectoryExists(virtualFolderPath))
- {
- throw new DirectoryNotFoundException(string.Format("The media collection {0} does not exist", virtualFolderName));
- }
-
- var shortcut = Directory.EnumerateFiles(virtualFolderPath, ShortcutFileSearch, SearchOption.AllDirectories).FirstOrDefault(f => _fileSystem.ResolveShortcut(f).Equals(mediaPath, StringComparison.OrdinalIgnoreCase));
-
- if (!string.IsNullOrEmpty(shortcut))
- {
- _fileSystem.DeleteFile(shortcut);
- }
-
- var libraryOptions = CollectionFolder.GetLibraryOptions(virtualFolderPath);
-
- libraryOptions.PathInfos = libraryOptions
- .PathInfos
- .Where(i => !string.Equals(i.Path, mediaPath, StringComparison.Ordinal))
- .ToArray();
-
- CollectionFolder.SaveLibraryOptions(virtualFolderPath, libraryOptions);
- }
- }
-} \ No newline at end of file
diff --git a/MediaBrowser.Server.Implementations/Library/LocalTrailerPostScanTask.cs b/MediaBrowser.Server.Implementations/Library/LocalTrailerPostScanTask.cs
deleted file mode 100644
index 78107b82d..000000000
--- a/MediaBrowser.Server.Implementations/Library/LocalTrailerPostScanTask.cs
+++ /dev/null
@@ -1,102 +0,0 @@
-using MediaBrowser.Controller.Channels;
-using MediaBrowser.Controller.Entities;
-using MediaBrowser.Controller.Library;
-using MediaBrowser.Model.Entities;
-using System;
-using System.Linq;
-using System.Threading;
-using System.Threading.Tasks;
-using MediaBrowser.Controller.Entities.Movies;
-using MediaBrowser.Controller.Entities.TV;
-
-namespace MediaBrowser.Server.Implementations.Library
-{
- public class LocalTrailerPostScanTask : ILibraryPostScanTask
- {
- private readonly ILibraryManager _libraryManager;
- private readonly IChannelManager _channelManager;
-
- public LocalTrailerPostScanTask(ILibraryManager libraryManager, IChannelManager channelManager)
- {
- _libraryManager = libraryManager;
- _channelManager = channelManager;
- }
-
- public async Task Run(IProgress<double> progress, CancellationToken cancellationToken)
- {
- var items = _libraryManager.GetItemList(new InternalItemsQuery
- {
- IncludeItemTypes = new[] { typeof(BoxSet).Name, typeof(Game).Name, typeof(Movie).Name, typeof(Series).Name },
- Recursive = true
-
- }).OfType<IHasTrailers>().ToList();
-
- var trailerTypes = Enum.GetNames(typeof(TrailerType))
- .Select(i => (TrailerType)Enum.Parse(typeof(TrailerType), i, true))
- .Except(new[] { TrailerType.LocalTrailer })
- .ToArray();
-
- var trailers = _libraryManager.GetItemList(new InternalItemsQuery
- {
- IncludeItemTypes = new[] { typeof(Trailer).Name },
- TrailerTypes = trailerTypes,
- Recursive = true
-
- }).ToArray();
-
- var numComplete = 0;
-
- foreach (var item in items)
- {
- cancellationToken.ThrowIfCancellationRequested();
-
- await AssignTrailers(item, trailers).ConfigureAwait(false);
-
- numComplete++;
- double percent = numComplete;
- percent /= items.Count;
- progress.Report(percent * 100);
- }
-
- progress.Report(100);
- }
-
- private async Task AssignTrailers(IHasTrailers item, BaseItem[] channelTrailers)
- {
- if (item is Game)
- {
- return;
- }
-
- var imdbId = item.GetProviderId(MetadataProviders.Imdb);
- var tmdbId = item.GetProviderId(MetadataProviders.Tmdb);
-
- var trailers = channelTrailers.Where(i =>
- {
- if (!string.IsNullOrWhiteSpace(imdbId) &&
- string.Equals(imdbId, i.GetProviderId(MetadataProviders.Imdb), StringComparison.OrdinalIgnoreCase))
- {
- return true;
- }
- if (!string.IsNullOrWhiteSpace(tmdbId) &&
- string.Equals(tmdbId, i.GetProviderId(MetadataProviders.Tmdb), StringComparison.OrdinalIgnoreCase))
- {
- return true;
- }
- return false;
- });
-
- var trailerIds = trailers.Select(i => i.Id)
- .ToList();
-
- if (!trailerIds.SequenceEqual(item.RemoteTrailerIds))
- {
- item.RemoteTrailerIds = trailerIds;
-
- var baseItem = (BaseItem)item;
- await baseItem.UpdateToRepository(ItemUpdateType.MetadataImport, CancellationToken.None)
- .ConfigureAwait(false);
- }
- }
- }
-}
diff --git a/MediaBrowser.Server.Implementations/Library/MediaSourceManager.cs b/MediaBrowser.Server.Implementations/Library/MediaSourceManager.cs
deleted file mode 100644
index 0f1931dda..000000000
--- a/MediaBrowser.Server.Implementations/Library/MediaSourceManager.cs
+++ /dev/null
@@ -1,648 +0,0 @@
-using MediaBrowser.Common.Extensions;
-using MediaBrowser.Controller.Entities;
-using MediaBrowser.Controller.Library;
-using MediaBrowser.Controller.MediaEncoding;
-using MediaBrowser.Controller.Persistence;
-using MediaBrowser.Model.Dto;
-using MediaBrowser.Model.Entities;
-using MediaBrowser.Model.Logging;
-using MediaBrowser.Model.MediaInfo;
-using MediaBrowser.Model.Serialization;
-using System;
-using System.Collections.Concurrent;
-using System.Collections.Generic;
-using System.Linq;
-using System.Threading;
-using System.Threading.Tasks;
-using MediaBrowser.Common.IO;
-using MediaBrowser.Controller.IO;
-using MediaBrowser.Model.IO;
-using MediaBrowser.Model.Configuration;
-
-namespace MediaBrowser.Server.Implementations.Library
-{
- public class MediaSourceManager : IMediaSourceManager, IDisposable
- {
- private readonly IItemRepository _itemRepo;
- private readonly IUserManager _userManager;
- private readonly ILibraryManager _libraryManager;
- private readonly IJsonSerializer _jsonSerializer;
- private readonly IFileSystem _fileSystem;
-
- private IMediaSourceProvider[] _providers;
- private readonly ILogger _logger;
- private readonly IUserDataManager _userDataManager;
-
- public MediaSourceManager(IItemRepository itemRepo, IUserManager userManager, ILibraryManager libraryManager, ILogger logger, IJsonSerializer jsonSerializer, IFileSystem fileSystem, IUserDataManager userDataManager)
- {
- _itemRepo = itemRepo;
- _userManager = userManager;
- _libraryManager = libraryManager;
- _logger = logger;
- _jsonSerializer = jsonSerializer;
- _fileSystem = fileSystem;
- _userDataManager = userDataManager;
- }
-
- public void AddParts(IEnumerable<IMediaSourceProvider> providers)
- {
- _providers = providers.ToArray();
- }
-
- public IEnumerable<MediaStream> GetMediaStreams(MediaStreamQuery query)
- {
- var list = _itemRepo.GetMediaStreams(query)
- .ToList();
-
- foreach (var stream in list)
- {
- stream.SupportsExternalStream = StreamSupportsExternalStream(stream);
- }
-
- return list;
- }
-
- private bool StreamSupportsExternalStream(MediaStream stream)
- {
- if (stream.IsExternal)
- {
- return true;
- }
-
- if (stream.IsTextSubtitleStream)
- {
- return true;
- }
-
- return false;
- }
-
- public IEnumerable<MediaStream> GetMediaStreams(string mediaSourceId)
- {
- var list = GetMediaStreams(new MediaStreamQuery
- {
- ItemId = new Guid(mediaSourceId)
- });
-
- return GetMediaStreamsForItem(list);
- }
-
- public IEnumerable<MediaStream> GetMediaStreams(Guid itemId)
- {
- var list = GetMediaStreams(new MediaStreamQuery
- {
- ItemId = itemId
- });
-
- return GetMediaStreamsForItem(list);
- }
-
- private IEnumerable<MediaStream> GetMediaStreamsForItem(IEnumerable<MediaStream> streams)
- {
- var list = streams.ToList();
-
- var subtitleStreams = list
- .Where(i => i.Type == MediaStreamType.Subtitle)
- .ToList();
-
- if (subtitleStreams.Count > 0)
- {
- foreach (var subStream in subtitleStreams)
- {
- subStream.SupportsExternalStream = StreamSupportsExternalStream(subStream);
- }
- }
-
- return list;
- }
-
- public async Task<IEnumerable<MediaSourceInfo>> GetPlayackMediaSources(string id, string userId, bool enablePathSubstitution, string[] supportedLiveMediaTypes, CancellationToken cancellationToken)
- {
- var item = _libraryManager.GetItemById(id);
-
- var hasMediaSources = (IHasMediaSources)item;
- User user = null;
-
- if (!string.IsNullOrWhiteSpace(userId))
- {
- user = _userManager.GetUserById(userId);
- }
-
- var mediaSources = GetStaticMediaSources(hasMediaSources, enablePathSubstitution, user);
- var dynamicMediaSources = await GetDynamicMediaSources(hasMediaSources, cancellationToken).ConfigureAwait(false);
-
- var list = new List<MediaSourceInfo>();
-
- list.AddRange(mediaSources);
-
- foreach (var source in dynamicMediaSources)
- {
- if (user != null)
- {
- SetUserProperties(hasMediaSources, source, user);
- }
- if (source.Protocol == MediaProtocol.File)
- {
- // TODO: Path substitution
- if (!_fileSystem.FileExists(source.Path))
- {
- source.SupportsDirectStream = false;
- }
- }
- else if (source.Protocol == MediaProtocol.Http)
- {
- // TODO: Allow this when the source is plain http, e.g. not HLS or Mpeg Dash
- source.SupportsDirectStream = false;
- }
- else
- {
- source.SupportsDirectStream = false;
- }
-
- list.Add(source);
- }
-
- foreach (var source in list)
- {
- if (user != null)
- {
- if (string.Equals(item.MediaType, MediaType.Audio, StringComparison.OrdinalIgnoreCase))
- {
- if (!user.Policy.EnableAudioPlaybackTranscoding)
- {
- source.SupportsTranscoding = false;
- }
- }
- }
- }
-
- return SortMediaSources(list).Where(i => i.Type != MediaSourceType.Placeholder);
- }
-
- private async Task<IEnumerable<MediaSourceInfo>> GetDynamicMediaSources(IHasMediaSources item, CancellationToken cancellationToken)
- {
- var tasks = _providers.Select(i => GetDynamicMediaSources(item, i, cancellationToken));
- var results = await Task.WhenAll(tasks).ConfigureAwait(false);
-
- return results.SelectMany(i => i.ToList());
- }
-
- private async Task<IEnumerable<MediaSourceInfo>> GetDynamicMediaSources(IHasMediaSources item, IMediaSourceProvider provider, CancellationToken cancellationToken)
- {
- try
- {
- var sources = await provider.GetMediaSources(item, cancellationToken).ConfigureAwait(false);
- var list = sources.ToList();
-
- foreach (var mediaSource in list)
- {
- SetKeyProperties(provider, mediaSource);
- }
-
- return list;
- }
- catch (Exception ex)
- {
- _logger.ErrorException("Error getting media sources", ex);
- return new List<MediaSourceInfo>();
- }
- }
-
- private void SetKeyProperties(IMediaSourceProvider provider, MediaSourceInfo mediaSource)
- {
- var prefix = provider.GetType().FullName.GetMD5().ToString("N") + LiveStreamIdDelimeter;
-
- if (!string.IsNullOrWhiteSpace(mediaSource.OpenToken) && !mediaSource.OpenToken.StartsWith(prefix, StringComparison.OrdinalIgnoreCase))
- {
- mediaSource.OpenToken = prefix + mediaSource.OpenToken;
- }
-
- if (!string.IsNullOrWhiteSpace(mediaSource.LiveStreamId) && !mediaSource.LiveStreamId.StartsWith(prefix, StringComparison.OrdinalIgnoreCase))
- {
- mediaSource.LiveStreamId = prefix + mediaSource.LiveStreamId;
- }
- }
-
- public async Task<MediaSourceInfo> GetMediaSource(IHasMediaSources item, string mediaSourceId, string liveStreamId, bool enablePathSubstitution, CancellationToken cancellationToken)
- {
- if (!string.IsNullOrWhiteSpace(liveStreamId))
- {
- return await GetLiveStream(liveStreamId, cancellationToken).ConfigureAwait(false);
- }
- //await _liveStreamSemaphore.WaitAsync(cancellationToken).ConfigureAwait(false);
-
- //try
- //{
- // var stream = _openStreams.Values.FirstOrDefault(i => string.Equals(i.MediaSource.Id, mediaSourceId, StringComparison.OrdinalIgnoreCase));
-
- // if (stream != null)
- // {
- // return stream.MediaSource;
- // }
- //}
- //finally
- //{
- // _liveStreamSemaphore.Release();
- //}
-
- var sources = await GetPlayackMediaSources(item.Id.ToString("N"), null, enablePathSubstitution, new[] { MediaType.Audio, MediaType.Video },
- CancellationToken.None).ConfigureAwait(false);
-
- return sources.FirstOrDefault(i => string.Equals(i.Id, mediaSourceId, StringComparison.OrdinalIgnoreCase));
- }
-
- public IEnumerable<MediaSourceInfo> GetStaticMediaSources(IHasMediaSources item, bool enablePathSubstitution, User user = null)
- {
- if (item == null)
- {
- throw new ArgumentNullException("item");
- }
-
- if (!(item is Video))
- {
- return item.GetMediaSources(enablePathSubstitution);
- }
-
- var sources = item.GetMediaSources(enablePathSubstitution).ToList();
-
- if (user != null)
- {
- foreach (var source in sources)
- {
- SetUserProperties(item, source, user);
- }
- }
-
- return sources;
- }
-
- private void SetUserProperties(IHasUserData item, MediaSourceInfo source, User user)
- {
- var userData = item == null ? new UserItemData() : _userDataManager.GetUserData(user, item);
-
- var allowRememberingSelection = item == null || item.EnableRememberingTrackSelections;
-
- SetDefaultAudioStreamIndex(source, userData, user, allowRememberingSelection);
- SetDefaultSubtitleStreamIndex(source, userData, user, allowRememberingSelection);
- }
-
- private void SetDefaultSubtitleStreamIndex(MediaSourceInfo source, UserItemData userData, User user, bool allowRememberingSelection)
- {
- if (userData.SubtitleStreamIndex.HasValue && user.Configuration.RememberSubtitleSelections && user.Configuration.SubtitleMode != SubtitlePlaybackMode.None && allowRememberingSelection)
- {
- var index = userData.SubtitleStreamIndex.Value;
- // Make sure the saved index is still valid
- if (index == -1 || source.MediaStreams.Any(i => i.Type == MediaStreamType.Subtitle && i.Index == index))
- {
- source.DefaultSubtitleStreamIndex = index;
- return;
- }
- }
-
- var preferredSubs = string.IsNullOrEmpty(user.Configuration.SubtitleLanguagePreference)
- ? new List<string>() : new List<string> { user.Configuration.SubtitleLanguagePreference };
-
- var defaultAudioIndex = source.DefaultAudioStreamIndex;
- var audioLangage = defaultAudioIndex == null
- ? null
- : source.MediaStreams.Where(i => i.Type == MediaStreamType.Audio && i.Index == defaultAudioIndex).Select(i => i.Language).FirstOrDefault();
-
- source.DefaultSubtitleStreamIndex = MediaStreamSelector.GetDefaultSubtitleStreamIndex(source.MediaStreams,
- preferredSubs,
- user.Configuration.SubtitleMode,
- audioLangage);
-
- MediaStreamSelector.SetSubtitleStreamScores(source.MediaStreams, preferredSubs,
- user.Configuration.SubtitleMode, audioLangage);
- }
-
- private void SetDefaultAudioStreamIndex(MediaSourceInfo source, UserItemData userData, User user, bool allowRememberingSelection)
- {
- if (userData.AudioStreamIndex.HasValue && user.Configuration.RememberAudioSelections && allowRememberingSelection)
- {
- var index = userData.AudioStreamIndex.Value;
- // Make sure the saved index is still valid
- if (source.MediaStreams.Any(i => i.Type == MediaStreamType.Audio && i.Index == index))
- {
- source.DefaultAudioStreamIndex = index;
- return;
- }
- }
-
- var preferredAudio = string.IsNullOrEmpty(user.Configuration.AudioLanguagePreference)
- ? new string[] { }
- : new[] { user.Configuration.AudioLanguagePreference };
-
- source.DefaultAudioStreamIndex = MediaStreamSelector.GetDefaultAudioStreamIndex(source.MediaStreams, preferredAudio, user.Configuration.PlayDefaultAudioTrack);
- }
-
- private IEnumerable<MediaSourceInfo> SortMediaSources(IEnumerable<MediaSourceInfo> sources)
- {
- return sources.OrderBy(i =>
- {
- if (i.VideoType.HasValue && i.VideoType.Value == VideoType.VideoFile)
- {
- return 0;
- }
-
- return 1;
-
- }).ThenBy(i => i.Video3DFormat.HasValue ? 1 : 0)
- .ThenByDescending(i =>
- {
- var stream = i.VideoStream;
-
- return stream == null || stream.Width == null ? 0 : stream.Width.Value;
- })
- .ToList();
- }
-
- private readonly Dictionary<string, LiveStreamInfo> _openStreams = new Dictionary<string, LiveStreamInfo>(StringComparer.OrdinalIgnoreCase);
- private readonly SemaphoreSlim _liveStreamSemaphore = new SemaphoreSlim(1, 1);
-
- public async Task<LiveStreamResponse> OpenLiveStream(LiveStreamRequest request, bool enableAutoClose, CancellationToken cancellationToken)
- {
- await _liveStreamSemaphore.WaitAsync(cancellationToken).ConfigureAwait(false);
-
- try
- {
- var tuple = GetProvider(request.OpenToken);
- var provider = tuple.Item1;
-
- var mediaSourceTuple = await provider.OpenMediaSource(tuple.Item2, cancellationToken).ConfigureAwait(false);
-
- var mediaSource = mediaSourceTuple.Item1;
-
- if (string.IsNullOrWhiteSpace(mediaSource.LiveStreamId))
- {
- throw new InvalidOperationException(string.Format("{0} returned null LiveStreamId", provider.GetType().Name));
- }
-
- SetKeyProperties(provider, mediaSource);
-
- var info = new LiveStreamInfo
- {
- Date = DateTime.UtcNow,
- EnableCloseTimer = enableAutoClose,
- Id = mediaSource.LiveStreamId,
- MediaSource = mediaSource,
- DirectStreamProvider = mediaSourceTuple.Item2
- };
-
- _openStreams[mediaSource.LiveStreamId] = info;
-
- if (enableAutoClose)
- {
- StartCloseTimer();
- }
-
- var json = _jsonSerializer.SerializeToString(mediaSource);
- _logger.Debug("Live stream opened: " + json);
- var clone = _jsonSerializer.DeserializeFromString<MediaSourceInfo>(json);
-
- if (!string.IsNullOrWhiteSpace(request.UserId))
- {
- var user = _userManager.GetUserById(request.UserId);
- var item = string.IsNullOrWhiteSpace(request.ItemId)
- ? null
- : _libraryManager.GetItemById(request.ItemId);
- SetUserProperties(item, clone, user);
- }
-
- return new LiveStreamResponse
- {
- MediaSource = clone
- };
- }
- finally
- {
- _liveStreamSemaphore.Release();
- }
- }
-
- public async Task<Tuple<MediaSourceInfo, IDirectStreamProvider>> GetLiveStreamWithDirectStreamProvider(string id, CancellationToken cancellationToken)
- {
- if (string.IsNullOrWhiteSpace(id))
- {
- throw new ArgumentNullException("id");
- }
-
- _logger.Debug("Getting already opened live stream {0}", id);
-
- await _liveStreamSemaphore.WaitAsync(cancellationToken).ConfigureAwait(false);
-
- try
- {
- LiveStreamInfo info;
- if (_openStreams.TryGetValue(id, out info))
- {
- return new Tuple<MediaSourceInfo, IDirectStreamProvider>(info.MediaSource, info.DirectStreamProvider);
- }
- else
- {
- throw new ResourceNotFoundException();
- }
- }
- finally
- {
- _liveStreamSemaphore.Release();
- }
- }
-
- public async Task<MediaSourceInfo> GetLiveStream(string id, CancellationToken cancellationToken)
- {
- var result = await GetLiveStreamWithDirectStreamProvider(id, cancellationToken).ConfigureAwait(false);
- return result.Item1;
- }
-
- public async Task PingLiveStream(string id, CancellationToken cancellationToken)
- {
- await _liveStreamSemaphore.WaitAsync(cancellationToken).ConfigureAwait(false);
-
- try
- {
- LiveStreamInfo info;
- if (_openStreams.TryGetValue(id, out info))
- {
- info.Date = DateTime.UtcNow;
- }
- else
- {
- _logger.Error("Failed to ping live stream {0}", id);
- }
- }
- finally
- {
- _liveStreamSemaphore.Release();
- }
- }
-
- private async Task CloseLiveStreamWithProvider(IMediaSourceProvider provider, string streamId)
- {
- _logger.Info("Closing live stream {0} with provider {1}", streamId, provider.GetType().Name);
-
- try
- {
- await provider.CloseMediaSource(streamId).ConfigureAwait(false);
- }
- catch (NotImplementedException)
- {
- }
- catch (Exception ex)
- {
- _logger.ErrorException("Error closing live stream {0}", ex, streamId);
- }
- }
-
- public async Task CloseLiveStream(string id)
- {
- if (string.IsNullOrWhiteSpace(id))
- {
- throw new ArgumentNullException("id");
- }
-
- await _liveStreamSemaphore.WaitAsync().ConfigureAwait(false);
-
- try
- {
- LiveStreamInfo current;
-
- if (_openStreams.TryGetValue(id, out current))
- {
- _openStreams.Remove(id);
- current.Closed = true;
-
- if (current.MediaSource.RequiresClosing)
- {
- var tuple = GetProvider(id);
-
- await CloseLiveStreamWithProvider(tuple.Item1, tuple.Item2).ConfigureAwait(false);
- }
-
- if (_openStreams.Count == 0)
- {
- StopCloseTimer();
- }
- }
- }
- finally
- {
- _liveStreamSemaphore.Release();
- }
- }
-
- // Do not use a pipe here because Roku http requests to the server will fail, without any explicit error message.
- private const char LiveStreamIdDelimeter = '_';
-
- private Tuple<IMediaSourceProvider, string> GetProvider(string key)
- {
- if (string.IsNullOrWhiteSpace(key))
- {
- throw new ArgumentException("key");
- }
-
- var keys = key.Split(new[] { LiveStreamIdDelimeter }, 2);
-
- var provider = _providers.FirstOrDefault(i => string.Equals(i.GetType().FullName.GetMD5().ToString("N"), keys[0], StringComparison.OrdinalIgnoreCase));
-
- var splitIndex = key.IndexOf(LiveStreamIdDelimeter);
- var keyId = key.Substring(splitIndex + 1);
-
- return new Tuple<IMediaSourceProvider, string>(provider, keyId);
- }
-
- private Timer _closeTimer;
- private readonly TimeSpan _openStreamMaxAge = TimeSpan.FromSeconds(180);
-
- private void StartCloseTimer()
- {
- StopCloseTimer();
-
- _closeTimer = new Timer(CloseTimerCallback, null, _openStreamMaxAge, _openStreamMaxAge);
- }
-
- private void StopCloseTimer()
- {
- var timer = _closeTimer;
-
- if (timer != null)
- {
- _closeTimer = null;
- timer.Dispose();
- }
- }
-
- private async void CloseTimerCallback(object state)
- {
- List<LiveStreamInfo> infos;
- await _liveStreamSemaphore.WaitAsync().ConfigureAwait(false);
-
- try
- {
- infos = _openStreams
- .Values
- .Where(i => i.EnableCloseTimer && DateTime.UtcNow - i.Date > _openStreamMaxAge)
- .ToList();
- }
- finally
- {
- _liveStreamSemaphore.Release();
- }
-
- foreach (var info in infos)
- {
- if (!info.Closed)
- {
- try
- {
- await CloseLiveStream(info.Id).ConfigureAwait(false);
- }
- catch (Exception ex)
- {
- _logger.ErrorException("Error closing media source", ex);
- }
- }
- }
- }
-
- /// <summary>
- /// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources.
- /// </summary>
- public void Dispose()
- {
- StopCloseTimer();
- Dispose(true);
- }
-
- private readonly object _disposeLock = new object();
- /// <summary>
- /// Releases unmanaged and - optionally - managed resources.
- /// </summary>
- /// <param name="dispose"><c>true</c> to release both managed and unmanaged resources; <c>false</c> to release only unmanaged resources.</param>
- protected virtual void Dispose(bool dispose)
- {
- if (dispose)
- {
- lock (_disposeLock)
- {
- foreach (var key in _openStreams.Keys.ToList())
- {
- var task = CloseLiveStream(key);
-
- Task.WaitAll(task);
- }
- }
- }
- }
-
- private class LiveStreamInfo
- {
- public DateTime Date;
- public bool EnableCloseTimer;
- public string Id;
- public bool Closed;
- public MediaSourceInfo MediaSource;
- public IDirectStreamProvider DirectStreamProvider;
- }
- }
-} \ No newline at end of file
diff --git a/MediaBrowser.Server.Implementations/Library/MusicManager.cs b/MediaBrowser.Server.Implementations/Library/MusicManager.cs
deleted file mode 100644
index 3ff434898..000000000
--- a/MediaBrowser.Server.Implementations/Library/MusicManager.cs
+++ /dev/null
@@ -1,157 +0,0 @@
-using MediaBrowser.Controller.Entities;
-using MediaBrowser.Controller.Entities.Audio;
-using MediaBrowser.Controller.Library;
-using MediaBrowser.Controller.Playlists;
-using System;
-using System.Collections.Generic;
-using System.Linq;
-
-namespace MediaBrowser.Server.Implementations.Library
-{
- public class MusicManager : IMusicManager
- {
- private readonly ILibraryManager _libraryManager;
-
- public MusicManager(ILibraryManager libraryManager)
- {
- _libraryManager = libraryManager;
- }
-
- public IEnumerable<Audio> GetInstantMixFromSong(Audio item, User user)
- {
- var list = new List<Audio>
- {
- item
- };
-
- return list.Concat(GetInstantMixFromGenres(item.Genres, user));
- }
-
- public IEnumerable<Audio> GetInstantMixFromArtist(MusicArtist artist, User user)
- {
- var genres = user.RootFolder
- .GetRecursiveChildren(user, new InternalItemsQuery(user)
- {
- IncludeItemTypes = new[] { typeof(Audio).Name }
- })
- .Cast<Audio>()
- .Where(i => i.HasAnyArtist(artist.Name))
- .SelectMany(i => i.Genres)
- .Concat(artist.Genres)
- .Distinct(StringComparer.OrdinalIgnoreCase);
-
- return GetInstantMixFromGenres(genres, user);
- }
-
- public IEnumerable<Audio> GetInstantMixFromAlbum(MusicAlbum item, User user)
- {
- var genres = item
- .GetRecursiveChildren(user, new InternalItemsQuery(user)
- {
- IncludeItemTypes = new[] { typeof(Audio).Name }
- })
- .Cast<Audio>()
- .SelectMany(i => i.Genres)
- .Concat(item.Genres)
- .DistinctNames();
-
- return GetInstantMixFromGenres(genres, user);
- }
-
- public IEnumerable<Audio> GetInstantMixFromFolder(Folder item, User user)
- {
- var genres = item
- .GetRecursiveChildren(user, new InternalItemsQuery(user)
- {
- IncludeItemTypes = new[] {typeof(Audio).Name}
- })
- .Cast<Audio>()
- .SelectMany(i => i.Genres)
- .Concat(item.Genres)
- .DistinctNames();
-
- return GetInstantMixFromGenres(genres, user);
- }
-
- public IEnumerable<Audio> GetInstantMixFromPlaylist(Playlist item, User user)
- {
- var genres = item
- .GetRecursiveChildren(user, new InternalItemsQuery(user)
- {
- IncludeItemTypes = new[] { typeof(Audio).Name }
- })
- .Cast<Audio>()
- .SelectMany(i => i.Genres)
- .Concat(item.Genres)
- .DistinctNames();
-
- return GetInstantMixFromGenres(genres, user);
- }
-
- public IEnumerable<Audio> GetInstantMixFromGenres(IEnumerable<string> genres, User user)
- {
- var genreList = genres.ToList();
-
- var inputItems = _libraryManager.GetItemList(new InternalItemsQuery(user)
- {
- IncludeItemTypes = new[] { typeof(Audio).Name },
-
- Genres = genreList.ToArray()
-
- });
-
- var genresDictionary = genreList.ToDictionary(i => i, StringComparer.OrdinalIgnoreCase);
-
- return inputItems
- .Cast<Audio>()
- .Select(i => new Tuple<Audio, int>(i, i.Genres.Count(genresDictionary.ContainsKey)))
- .Where(i => i.Item2 > 0)
- .OrderByDescending(i => i.Item2)
- .ThenBy(i => Guid.NewGuid())
- .Select(i => i.Item1)
- .Take(100)
- .OrderBy(i => Guid.NewGuid());
- }
-
- public IEnumerable<Audio> GetInstantMixFromItem(BaseItem item, User user)
- {
- var genre = item as MusicGenre;
- if (genre != null)
- {
- return GetInstantMixFromGenres(new[] { item.Name }, user);
- }
-
- var playlist = item as Playlist;
- if (playlist != null)
- {
- return GetInstantMixFromPlaylist(playlist, user);
- }
-
- var album = item as MusicAlbum;
- if (album != null)
- {
- return GetInstantMixFromAlbum(album, user);
- }
-
- var artist = item as MusicArtist;
- if (artist != null)
- {
- return GetInstantMixFromArtist(artist, user);
- }
-
- var song = item as Audio;
- if (song != null)
- {
- return GetInstantMixFromSong(song, user);
- }
-
- var folder = item as Folder;
- if (folder != null)
- {
- return GetInstantMixFromFolder(folder, user);
- }
-
- return new Audio[] { };
- }
- }
-}
diff --git a/MediaBrowser.Server.Implementations/Library/PathExtensions.cs b/MediaBrowser.Server.Implementations/Library/PathExtensions.cs
deleted file mode 100644
index 6c0e3237e..000000000
--- a/MediaBrowser.Server.Implementations/Library/PathExtensions.cs
+++ /dev/null
@@ -1,45 +0,0 @@
-using System;
-using System.Text.RegularExpressions;
-
-namespace MediaBrowser.Server.Implementations.Library
-{
- public static class PathExtensions
- {
- /// <summary>
- /// Gets the attribute value.
- /// </summary>
- /// <param name="str">The STR.</param>
- /// <param name="attrib">The attrib.</param>
- /// <returns>System.String.</returns>
- /// <exception cref="System.ArgumentNullException">attrib</exception>
- public static string GetAttributeValue(this string str, string attrib)
- {
- if (string.IsNullOrEmpty(str))
- {
- throw new ArgumentNullException("str");
- }
-
- if (string.IsNullOrEmpty(attrib))
- {
- throw new ArgumentNullException("attrib");
- }
-
- string srch = "[" + attrib + "=";
- int start = str.IndexOf(srch, StringComparison.OrdinalIgnoreCase);
- if (start > -1)
- {
- start += srch.Length;
- int end = str.IndexOf(']', start);
- return str.Substring(start, end - start);
- }
- // for imdbid we also accept pattern matching
- if (string.Equals(attrib, "imdbid", StringComparison.OrdinalIgnoreCase))
- {
- var m = Regex.Match(str, "tt\\d{7}", RegexOptions.IgnoreCase);
- return m.Success ? m.Value : null;
- }
-
- return null;
- }
- }
-}
diff --git a/MediaBrowser.Server.Implementations/Library/ResolverHelper.cs b/MediaBrowser.Server.Implementations/Library/ResolverHelper.cs
deleted file mode 100644
index c7d9d39b8..000000000
--- a/MediaBrowser.Server.Implementations/Library/ResolverHelper.cs
+++ /dev/null
@@ -1,183 +0,0 @@
-using MediaBrowser.Controller.Entities;
-using MediaBrowser.Controller.Library;
-using MediaBrowser.Controller.Providers;
-using System;
-using System.IO;
-using System.Linq;
-using System.Text.RegularExpressions;
-using MediaBrowser.Common.IO;
-using MediaBrowser.Controller.IO;
-using MediaBrowser.Model.IO;
-
-namespace MediaBrowser.Server.Implementations.Library
-{
- /// <summary>
- /// Class ResolverHelper
- /// </summary>
- public static class ResolverHelper
- {
- /// <summary>
- /// Sets the initial item values.
- /// </summary>
- /// <param name="item">The item.</param>
- /// <param name="parent">The parent.</param>
- /// <param name="fileSystem">The file system.</param>
- /// <param name="libraryManager">The library manager.</param>
- /// <param name="directoryService">The directory service.</param>
- /// <exception cref="System.ArgumentException">Item must have a path</exception>
- public static void SetInitialItemValues(BaseItem item, Folder parent, IFileSystem fileSystem, ILibraryManager libraryManager, IDirectoryService directoryService)
- {
- // This version of the below method has no ItemResolveArgs, so we have to require the path already being set
- if (string.IsNullOrWhiteSpace(item.Path))
- {
- throw new ArgumentException("Item must have a Path");
- }
-
- // If the resolver didn't specify this
- if (parent != null)
- {
- item.SetParent(parent);
- }
-
- item.Id = libraryManager.GetNewItemId(item.Path, item.GetType());
-
- item.IsLocked = item.Path.IndexOf("[dontfetchmeta]", StringComparison.OrdinalIgnoreCase) != -1 ||
- item.GetParents().Any(i => i.IsLocked);
-
- // Make sure DateCreated and DateModified have values
- var fileInfo = directoryService.GetFile(item.Path);
- SetDateCreated(item, fileSystem, fileInfo);
-
- EnsureName(item, fileInfo);
- }
-
- /// <summary>
- /// Sets the initial item values.
- /// </summary>
- /// <param name="item">The item.</param>
- /// <param name="args">The args.</param>
- /// <param name="fileSystem">The file system.</param>
- /// <param name="libraryManager">The library manager.</param>
- public static void SetInitialItemValues(BaseItem item, ItemResolveArgs args, IFileSystem fileSystem, ILibraryManager libraryManager)
- {
- // If the resolver didn't specify this
- if (string.IsNullOrEmpty(item.Path))
- {
- item.Path = args.Path;
- }
-
- // If the resolver didn't specify this
- if (args.Parent != null)
- {
- item.SetParent(args.Parent);
- }
-
- item.Id = libraryManager.GetNewItemId(item.Path, item.GetType());
-
- // Make sure the item has a name
- EnsureName(item, args.FileInfo);
-
- item.IsLocked = item.Path.IndexOf("[dontfetchmeta]", StringComparison.OrdinalIgnoreCase) != -1 ||
- item.GetParents().Any(i => i.IsLocked);
-
- // Make sure DateCreated and DateModified have values
- EnsureDates(fileSystem, item, args);
- }
-
- /// <summary>
- /// Ensures the name.
- /// </summary>
- /// <param name="item">The item.</param>
- /// <param name="fileInfo">The file information.</param>
- private static void EnsureName(BaseItem item, FileSystemMetadata fileInfo)
- {
- // If the subclass didn't supply a name, add it here
- if (string.IsNullOrEmpty(item.Name) && !string.IsNullOrEmpty(item.Path))
- {
- item.Name = GetDisplayName(fileInfo.Name, fileInfo.IsDirectory);
- }
- }
-
- /// <summary>
- /// Gets the display name.
- /// </summary>
- /// <param name="path">The path.</param>
- /// <param name="isDirectory">if set to <c>true</c> [is directory].</param>
- /// <returns>System.String.</returns>
- private static string GetDisplayName(string path, bool isDirectory)
- {
- return isDirectory ? Path.GetFileName(path) : Path.GetFileNameWithoutExtension(path);
- }
-
- /// <summary>
- /// The MB name regex
- /// </summary>
- private static readonly Regex MbNameRegex = new Regex(@"(\[.*?\])", RegexOptions.Compiled);
-
- internal static string StripBrackets(string inputString)
- {
- var output = MbNameRegex.Replace(inputString, string.Empty).Trim();
- return Regex.Replace(output, @"\s+", " ");
- }
-
- /// <summary>
- /// Ensures DateCreated and DateModified have values
- /// </summary>
- /// <param name="fileSystem">The file system.</param>
- /// <param name="item">The item.</param>
- /// <param name="args">The args.</param>
- private static void EnsureDates(IFileSystem fileSystem, BaseItem item, ItemResolveArgs args)
- {
- if (fileSystem == null)
- {
- throw new ArgumentNullException("fileSystem");
- }
- if (item == null)
- {
- throw new ArgumentNullException("item");
- }
- if (args == null)
- {
- throw new ArgumentNullException("args");
- }
-
- // See if a different path came out of the resolver than what went in
- if (!string.Equals(args.Path, item.Path, StringComparison.OrdinalIgnoreCase))
- {
- var childData = args.IsDirectory ? args.GetFileSystemEntryByPath(item.Path) : null;
-
- if (childData != null)
- {
- SetDateCreated(item, fileSystem, childData);
- }
- else
- {
- var fileData = fileSystem.GetFileSystemInfo(item.Path);
-
- if (fileData.Exists)
- {
- SetDateCreated(item, fileSystem, fileData);
- }
- }
- }
- else
- {
- SetDateCreated(item, fileSystem, args.FileInfo);
- }
- }
-
- private static void SetDateCreated(BaseItem item, IFileSystem fileSystem, FileSystemMetadata info)
- {
- var config = BaseItem.ConfigurationManager.GetMetadataConfiguration();
-
- if (config.UseFileCreationTimeForDateAdded)
- {
- item.DateCreated = fileSystem.GetCreationTimeUtc(info);
- }
- else
- {
- item.DateCreated = DateTime.UtcNow;
- }
- }
- }
-}
diff --git a/MediaBrowser.Server.Implementations/Library/Resolvers/Audio/AudioResolver.cs b/MediaBrowser.Server.Implementations/Library/Resolvers/Audio/AudioResolver.cs
deleted file mode 100644
index 039a17100..000000000
--- a/MediaBrowser.Server.Implementations/Library/Resolvers/Audio/AudioResolver.cs
+++ /dev/null
@@ -1,68 +0,0 @@
-using MediaBrowser.Controller.Library;
-using MediaBrowser.Controller.Resolvers;
-using MediaBrowser.Model.Entities;
-using System;
-
-namespace MediaBrowser.Server.Implementations.Library.Resolvers.Audio
-{
- /// <summary>
- /// Class AudioResolver
- /// </summary>
- public class AudioResolver : ItemResolver<Controller.Entities.Audio.Audio>
- {
- private readonly ILibraryManager _libraryManager;
-
- public AudioResolver(ILibraryManager libraryManager)
- {
- _libraryManager = libraryManager;
- }
-
- /// <summary>
- /// Gets the priority.
- /// </summary>
- /// <value>The priority.</value>
- public override ResolverPriority Priority
- {
- get { return ResolverPriority.Last; }
- }
-
- /// <summary>
- /// Resolves the specified args.
- /// </summary>
- /// <param name="args">The args.</param>
- /// <returns>Entities.Audio.Audio.</returns>
- protected override Controller.Entities.Audio.Audio Resolve(ItemResolveArgs args)
- {
- // Return audio if the path is a file and has a matching extension
-
- if (!args.IsDirectory)
- {
- var libraryOptions = args.GetLibraryOptions();
-
- if (_libraryManager.IsAudioFile(args.Path, libraryOptions))
- {
- var collectionType = args.GetCollectionType();
-
- var isMixed = string.IsNullOrWhiteSpace(collectionType);
-
- // For conflicting extensions, give priority to videos
- if (isMixed && _libraryManager.IsVideoFile(args.Path, libraryOptions))
- {
- return null;
- }
-
- var isStandalone = args.Parent == null;
-
- if (isStandalone ||
- string.Equals(collectionType, CollectionType.Music, StringComparison.OrdinalIgnoreCase) ||
- isMixed)
- {
- return new Controller.Entities.Audio.Audio();
- }
- }
- }
-
- return null;
- }
- }
-}
diff --git a/MediaBrowser.Server.Implementations/Library/Resolvers/Audio/MusicAlbumResolver.cs b/MediaBrowser.Server.Implementations/Library/Resolvers/Audio/MusicAlbumResolver.cs
deleted file mode 100644
index c1ac7d68c..000000000
--- a/MediaBrowser.Server.Implementations/Library/Resolvers/Audio/MusicAlbumResolver.cs
+++ /dev/null
@@ -1,173 +0,0 @@
-using MediaBrowser.Controller.Entities.Audio;
-using MediaBrowser.Controller.Library;
-using MediaBrowser.Controller.Providers;
-using MediaBrowser.Controller.Resolvers;
-using MediaBrowser.Model.Entities;
-using MediaBrowser.Model.Logging;
-using MediaBrowser.Naming.Audio;
-using MediaBrowser.Server.Implementations.Logging;
-using System;
-using System.Collections.Generic;
-using System.IO;
-using MediaBrowser.Common.IO;
-using MediaBrowser.Model.IO;
-using MediaBrowser.Controller.Configuration;
-using MediaBrowser.Controller.IO;
-using MediaBrowser.Model.Configuration;
-
-namespace MediaBrowser.Server.Implementations.Library.Resolvers.Audio
-{
- /// <summary>
- /// Class MusicAlbumResolver
- /// </summary>
- public class MusicAlbumResolver : ItemResolver<MusicAlbum>
- {
- private readonly ILogger _logger;
- private readonly IFileSystem _fileSystem;
- private readonly ILibraryManager _libraryManager;
-
- public MusicAlbumResolver(ILogger logger, IFileSystem fileSystem, ILibraryManager libraryManager)
- {
- _logger = logger;
- _fileSystem = fileSystem;
- _libraryManager = libraryManager;
- }
-
- /// <summary>
- /// Gets the priority.
- /// </summary>
- /// <value>The priority.</value>
- public override ResolverPriority Priority
- {
- get
- {
- // Behind special folder resolver
- return ResolverPriority.Second;
- }
- }
-
- /// <summary>
- /// Resolves the specified args.
- /// </summary>
- /// <param name="args">The args.</param>
- /// <returns>MusicAlbum.</returns>
- protected override MusicAlbum Resolve(ItemResolveArgs args)
- {
- if (!args.IsDirectory) return null;
-
- // Avoid mis-identifying top folders
- if (args.HasParent<MusicAlbum>()) return null;
- if (args.Parent.IsRoot) return null;
-
- var collectionType = args.GetCollectionType();
-
- var isMusicMediaFolder = string.Equals(collectionType, CollectionType.Music, StringComparison.OrdinalIgnoreCase);
-
- // If there's a collection type and it's not music, don't allow it.
- if (!isMusicMediaFolder)
- {
- return null;
- }
-
- return IsMusicAlbum(args) ? new MusicAlbum() : null;
- }
-
-
- /// <summary>
- /// Determine if the supplied file data points to a music album
- /// </summary>
- public bool IsMusicAlbum(string path, IDirectoryService directoryService, LibraryOptions libraryOptions)
- {
- return ContainsMusic(directoryService.GetFileSystemEntries(path), true, directoryService, _logger, _fileSystem, libraryOptions, _libraryManager);
- }
-
- /// <summary>
- /// Determine if the supplied resolve args should be considered a music album
- /// </summary>
- /// <param name="args">The args.</param>
- /// <returns><c>true</c> if [is music album] [the specified args]; otherwise, <c>false</c>.</returns>
- private bool IsMusicAlbum(ItemResolveArgs args)
- {
- // Args points to an album if parent is an Artist folder or it directly contains music
- if (args.IsDirectory)
- {
- //if (args.Parent is MusicArtist) return true; //saves us from testing children twice
- if (ContainsMusic(args.FileSystemChildren, true, args.DirectoryService, _logger, _fileSystem, args.GetLibraryOptions(), _libraryManager)) return true;
- }
-
- return false;
- }
-
- /// <summary>
- /// Determine if the supplied list contains what we should consider music
- /// </summary>
- private bool ContainsMusic(IEnumerable<FileSystemMetadata> list,
- bool allowSubfolders,
- IDirectoryService directoryService,
- ILogger logger,
- IFileSystem fileSystem,
- LibraryOptions libraryOptions,
- ILibraryManager libraryManager)
- {
- var discSubfolderCount = 0;
- var notMultiDisc = false;
-
- foreach (var fileSystemInfo in list)
- {
- if (fileSystemInfo.IsDirectory)
- {
- if (allowSubfolders)
- {
- var path = fileSystemInfo.FullName;
- var isMultiDisc = IsMultiDiscFolder(path, libraryOptions);
-
- if (isMultiDisc)
- {
- var hasMusic = ContainsMusic(directoryService.GetFileSystemEntries(path), false, directoryService, logger, fileSystem, libraryOptions, libraryManager);
-
- if (hasMusic)
- {
- logger.Debug("Found multi-disc folder: " + path);
- discSubfolderCount++;
- }
- }
- else
- {
- var hasMusic = ContainsMusic(directoryService.GetFileSystemEntries(path), false, directoryService, logger, fileSystem, libraryOptions, libraryManager);
-
- if (hasMusic)
- {
- // If there are folders underneath with music that are not multidisc, then this can't be a multi-disc album
- notMultiDisc = true;
- }
- }
- }
- }
-
- var fullName = fileSystemInfo.FullName;
-
- if (libraryManager.IsAudioFile(fullName, libraryOptions))
- {
- return true;
- }
- }
-
- if (notMultiDisc)
- {
- return false;
- }
-
- return discSubfolderCount > 0;
- }
-
- private bool IsMultiDiscFolder(string path, LibraryOptions libraryOptions)
- {
- var namingOptions = ((LibraryManager)_libraryManager).GetNamingOptions(libraryOptions);
-
- var parser = new AlbumParser(namingOptions, new PatternsLogger());
- var result = parser.ParseMultiPart(path);
-
- return result.IsMultiPart;
- }
- }
-}
diff --git a/MediaBrowser.Server.Implementations/Library/Resolvers/Audio/MusicArtistResolver.cs b/MediaBrowser.Server.Implementations/Library/Resolvers/Audio/MusicArtistResolver.cs
deleted file mode 100644
index be651b9c8..000000000
--- a/MediaBrowser.Server.Implementations/Library/Resolvers/Audio/MusicArtistResolver.cs
+++ /dev/null
@@ -1,94 +0,0 @@
-using MediaBrowser.Controller.Entities.Audio;
-using MediaBrowser.Controller.Library;
-using MediaBrowser.Controller.Resolvers;
-using MediaBrowser.Model.Entities;
-using MediaBrowser.Model.Logging;
-using System;
-using System.IO;
-using System.Linq;
-using MediaBrowser.Common.IO;
-using MediaBrowser.Model.IO;
-using MediaBrowser.Controller.Configuration;
-using MediaBrowser.Controller.IO;
-
-namespace MediaBrowser.Server.Implementations.Library.Resolvers.Audio
-{
- /// <summary>
- /// Class MusicArtistResolver
- /// </summary>
- public class MusicArtistResolver : ItemResolver<MusicArtist>
- {
- private readonly ILogger _logger;
- private readonly IFileSystem _fileSystem;
- private readonly ILibraryManager _libraryManager;
- private readonly IServerConfigurationManager _config;
-
- public MusicArtistResolver(ILogger logger, IFileSystem fileSystem, ILibraryManager libraryManager, IServerConfigurationManager config)
- {
- _logger = logger;
- _fileSystem = fileSystem;
- _libraryManager = libraryManager;
- _config = config;
- }
-
- /// <summary>
- /// Gets the priority.
- /// </summary>
- /// <value>The priority.</value>
- public override ResolverPriority Priority
- {
- get
- {
- // Behind special folder resolver
- return ResolverPriority.Second;
- }
- }
-
- /// <summary>
- /// Resolves the specified args.
- /// </summary>
- /// <param name="args">The args.</param>
- /// <returns>MusicArtist.</returns>
- protected override MusicArtist Resolve(ItemResolveArgs args)
- {
- if (!args.IsDirectory) return null;
-
- // Don't allow nested artists
- if (args.HasParent<MusicArtist>() || args.HasParent<MusicAlbum>())
- {
- return null;
- }
-
- var collectionType = args.GetCollectionType();
-
- var isMusicMediaFolder = string.Equals(collectionType, CollectionType.Music, StringComparison.OrdinalIgnoreCase);
-
- // If there's a collection type and it's not music, it can't be a series
- if (!isMusicMediaFolder)
- {
- return null;
- }
-
- if (args.ContainsFileSystemEntryByName("artist.nfo"))
- {
- return new MusicArtist();
- }
-
- if (_config.Configuration.EnableSimpleArtistDetection)
- {
- return null;
- }
-
- // Avoid mis-identifying top folders
- if (args.Parent.IsRoot) return null;
-
- var directoryService = args.DirectoryService;
-
- var albumResolver = new MusicAlbumResolver(_logger, _fileSystem, _libraryManager);
-
- // If we contain an album assume we are an artist folder
- return args.FileSystemChildren.Where(i => i.IsDirectory).Any(i => albumResolver.IsMusicAlbum(i.FullName, directoryService, args.GetLibraryOptions())) ? new MusicArtist() : null;
- }
-
- }
-}
diff --git a/MediaBrowser.Server.Implementations/Library/Resolvers/BaseVideoResolver.cs b/MediaBrowser.Server.Implementations/Library/Resolvers/BaseVideoResolver.cs
deleted file mode 100644
index 4dce16139..000000000
--- a/MediaBrowser.Server.Implementations/Library/Resolvers/BaseVideoResolver.cs
+++ /dev/null
@@ -1,297 +0,0 @@
-using MediaBrowser.Controller.Entities;
-using MediaBrowser.Controller.Library;
-using MediaBrowser.Model.Entities;
-using MediaBrowser.Naming.Video;
-using MediaBrowser.Server.Implementations.Logging;
-using System;
-using System.IO;
-
-namespace MediaBrowser.Server.Implementations.Library.Resolvers
-{
- /// <summary>
- /// Resolves a Path into a Video or Video subclass
- /// </summary>
- /// <typeparam name="T"></typeparam>
- public abstract class BaseVideoResolver<T> : Controller.Resolvers.ItemResolver<T>
- where T : Video, new()
- {
- protected readonly ILibraryManager LibraryManager;
-
- protected BaseVideoResolver(ILibraryManager libraryManager)
- {
- LibraryManager = libraryManager;
- }
-
- /// <summary>
- /// Resolves the specified args.
- /// </summary>
- /// <param name="args">The args.</param>
- /// <returns>`0.</returns>
- protected override T Resolve(ItemResolveArgs args)
- {
- return ResolveVideo<T>(args, false);
- }
-
- /// <summary>
- /// Resolves the video.
- /// </summary>
- /// <typeparam name="TVideoType">The type of the T video type.</typeparam>
- /// <param name="args">The args.</param>
- /// <param name="parseName">if set to <c>true</c> [parse name].</param>
- /// <returns>``0.</returns>
- protected TVideoType ResolveVideo<TVideoType>(ItemResolveArgs args, bool parseName)
- where TVideoType : Video, new()
- {
- var namingOptions = ((LibraryManager)LibraryManager).GetNamingOptions();
-
- // If the path is a file check for a matching extensions
- var parser = new Naming.Video.VideoResolver(namingOptions, new PatternsLogger());
-
- if (args.IsDirectory)
- {
- TVideoType video = null;
- VideoFileInfo videoInfo = null;
-
- // Loop through each child file/folder and see if we find a video
- foreach (var child in args.FileSystemChildren)
- {
- var filename = child.Name;
-
- if (child.IsDirectory)
- {
- if (IsDvdDirectory(filename))
- {
- videoInfo = parser.ResolveDirectory(args.Path);
-
- if (videoInfo == null)
- {
- return null;
- }
-
- video = new TVideoType
- {
- Path = args.Path,
- VideoType = VideoType.Dvd,
- ProductionYear = videoInfo.Year
- };
- break;
- }
- if (IsBluRayDirectory(filename))
- {
- videoInfo = parser.ResolveDirectory(args.Path);
-
- if (videoInfo == null)
- {
- return null;
- }
-
- video = new TVideoType
- {
- Path = args.Path,
- VideoType = VideoType.BluRay,
- ProductionYear = videoInfo.Year
- };
- break;
- }
- }
- else if (IsDvdFile(filename))
- {
- videoInfo = parser.ResolveDirectory(args.Path);
-
- if (videoInfo == null)
- {
- return null;
- }
-
- video = new TVideoType
- {
- Path = args.Path,
- VideoType = VideoType.Dvd,
- ProductionYear = videoInfo.Year
- };
- break;
- }
- }
-
- if (video != null)
- {
- video.Name = parseName ?
- videoInfo.Name :
- Path.GetFileName(args.Path);
-
- Set3DFormat(video, videoInfo);
- }
-
- return video;
- }
- else
- {
- var videoInfo = parser.Resolve(args.Path, false, false);
-
- if (videoInfo == null)
- {
- return null;
- }
-
- if (LibraryManager.IsVideoFile(args.Path, args.GetLibraryOptions()) || videoInfo.IsStub)
- {
- var path = args.Path;
-
- var video = new TVideoType
- {
- Path = path,
- IsInMixedFolder = true,
- ProductionYear = videoInfo.Year
- };
-
- SetVideoType(video, videoInfo);
-
- video.Name = parseName ?
- videoInfo.Name :
- Path.GetFileNameWithoutExtension(args.Path);
-
- Set3DFormat(video, videoInfo);
-
- return video;
- }
- }
-
- return null;
- }
-
- protected void SetVideoType(Video video, VideoFileInfo videoInfo)
- {
- var extension = Path.GetExtension(video.Path);
- video.VideoType = string.Equals(extension, ".iso", StringComparison.OrdinalIgnoreCase) ||
- string.Equals(extension, ".img", StringComparison.OrdinalIgnoreCase) ?
- VideoType.Iso :
- VideoType.VideoFile;
-
- video.IsShortcut = string.Equals(extension, ".strm", StringComparison.OrdinalIgnoreCase);
- video.IsPlaceHolder = videoInfo.IsStub;
-
- if (videoInfo.IsStub)
- {
- if (string.Equals(videoInfo.StubType, "dvd", StringComparison.OrdinalIgnoreCase))
- {
- video.VideoType = VideoType.Dvd;
- }
- else if (string.Equals(videoInfo.StubType, "hddvd", StringComparison.OrdinalIgnoreCase))
- {
- video.VideoType = VideoType.HdDvd;
- video.IsHD = true;
- }
- else if (string.Equals(videoInfo.StubType, "bluray", StringComparison.OrdinalIgnoreCase))
- {
- video.VideoType = VideoType.BluRay;
- video.IsHD = true;
- }
- else if (string.Equals(videoInfo.StubType, "hdtv", StringComparison.OrdinalIgnoreCase))
- {
- video.IsHD = true;
- }
- }
-
- SetIsoType(video);
- }
-
- protected void SetIsoType(Video video)
- {
- if (video.VideoType == VideoType.Iso)
- {
- if (video.Path.IndexOf("dvd", StringComparison.OrdinalIgnoreCase) != -1)
- {
- video.IsoType = IsoType.Dvd;
- }
- else if (video.Path.IndexOf("bluray", StringComparison.OrdinalIgnoreCase) != -1)
- {
- video.IsoType = IsoType.BluRay;
- }
- }
- }
-
- protected void Set3DFormat(Video video, bool is3D, string format3D)
- {
- if (is3D)
- {
- if (string.Equals(format3D, "fsbs", StringComparison.OrdinalIgnoreCase))
- {
- video.Video3DFormat = Video3DFormat.FullSideBySide;
- }
- else if (string.Equals(format3D, "ftab", StringComparison.OrdinalIgnoreCase))
- {
- video.Video3DFormat = Video3DFormat.FullTopAndBottom;
- }
- else if (string.Equals(format3D, "hsbs", StringComparison.OrdinalIgnoreCase))
- {
- video.Video3DFormat = Video3DFormat.HalfSideBySide;
- }
- else if (string.Equals(format3D, "htab", StringComparison.OrdinalIgnoreCase))
- {
- video.Video3DFormat = Video3DFormat.HalfTopAndBottom;
- }
- else if (string.Equals(format3D, "sbs", StringComparison.OrdinalIgnoreCase))
- {
- video.Video3DFormat = Video3DFormat.HalfSideBySide;
- }
- else if (string.Equals(format3D, "sbs3d", StringComparison.OrdinalIgnoreCase))
- {
- video.Video3DFormat = Video3DFormat.HalfSideBySide;
- }
- else if (string.Equals(format3D, "tab", StringComparison.OrdinalIgnoreCase))
- {
- video.Video3DFormat = Video3DFormat.HalfTopAndBottom;
- }
- else if (string.Equals(format3D, "mvc", StringComparison.OrdinalIgnoreCase))
- {
- video.Video3DFormat = Video3DFormat.MVC;
- }
- }
- }
-
- protected void Set3DFormat(Video video, VideoFileInfo videoInfo)
- {
- Set3DFormat(video, videoInfo.Is3D, videoInfo.Format3D);
- }
-
- protected void Set3DFormat(Video video)
- {
- var namingOptions = ((LibraryManager)LibraryManager).GetNamingOptions();
-
- var resolver = new Format3DParser(namingOptions, new PatternsLogger());
- var result = resolver.Parse(video.Path);
-
- Set3DFormat(video, result.Is3D, result.Format3D);
- }
-
- /// <summary>
- /// Determines whether [is DVD directory] [the specified directory name].
- /// </summary>
- /// <param name="directoryName">Name of the directory.</param>
- /// <returns><c>true</c> if [is DVD directory] [the specified directory name]; otherwise, <c>false</c>.</returns>
- protected bool IsDvdDirectory(string directoryName)
- {
- return string.Equals(directoryName, "video_ts", StringComparison.OrdinalIgnoreCase);
- }
-
- /// <summary>
- /// Determines whether [is DVD file] [the specified name].
- /// </summary>
- /// <param name="name">The name.</param>
- /// <returns><c>true</c> if [is DVD file] [the specified name]; otherwise, <c>false</c>.</returns>
- protected bool IsDvdFile(string name)
- {
- return string.Equals(name, "video_ts.ifo", StringComparison.OrdinalIgnoreCase);
- }
-
- /// <summary>
- /// Determines whether [is blu ray directory] [the specified directory name].
- /// </summary>
- /// <param name="directoryName">Name of the directory.</param>
- /// <returns><c>true</c> if [is blu ray directory] [the specified directory name]; otherwise, <c>false</c>.</returns>
- protected bool IsBluRayDirectory(string directoryName)
- {
- return string.Equals(directoryName, "bdmv", StringComparison.OrdinalIgnoreCase);
- }
- }
-}
diff --git a/MediaBrowser.Server.Implementations/Library/Resolvers/FolderResolver.cs b/MediaBrowser.Server.Implementations/Library/Resolvers/FolderResolver.cs
deleted file mode 100644
index ff07c5282..000000000
--- a/MediaBrowser.Server.Implementations/Library/Resolvers/FolderResolver.cs
+++ /dev/null
@@ -1,56 +0,0 @@
-using MediaBrowser.Controller.Entities;
-using MediaBrowser.Controller.Library;
-using MediaBrowser.Controller.Resolvers;
-
-namespace MediaBrowser.Server.Implementations.Library.Resolvers
-{
- /// <summary>
- /// Class FolderResolver
- /// </summary>
- public class FolderResolver : FolderResolver<Folder>
- {
- /// <summary>
- /// Gets the priority.
- /// </summary>
- /// <value>The priority.</value>
- public override ResolverPriority Priority
- {
- get { return ResolverPriority.Last; }
- }
-
- /// <summary>
- /// Resolves the specified args.
- /// </summary>
- /// <param name="args">The args.</param>
- /// <returns>Folder.</returns>
- protected override Folder Resolve(ItemResolveArgs args)
- {
- if (args.IsDirectory)
- {
- return new Folder();
- }
-
- return null;
- }
- }
-
- /// <summary>
- /// Class FolderResolver
- /// </summary>
- /// <typeparam name="TItemType">The type of the T item type.</typeparam>
- public abstract class FolderResolver<TItemType> : ItemResolver<TItemType>
- where TItemType : Folder, new()
- {
- /// <summary>
- /// Sets the initial item values.
- /// </summary>
- /// <param name="item">The item.</param>
- /// <param name="args">The args.</param>
- protected override void SetInitialItemValues(TItemType item, ItemResolveArgs args)
- {
- base.SetInitialItemValues(item, args);
-
- item.IsRoot = args.Parent == null;
- }
- }
-}
diff --git a/MediaBrowser.Server.Implementations/Library/Resolvers/ItemResolver.cs b/MediaBrowser.Server.Implementations/Library/Resolvers/ItemResolver.cs
deleted file mode 100644
index a03eda263..000000000
--- a/MediaBrowser.Server.Implementations/Library/Resolvers/ItemResolver.cs
+++ /dev/null
@@ -1,62 +0,0 @@
-using MediaBrowser.Controller.Entities;
-using MediaBrowser.Controller.Library;
-using MediaBrowser.Controller.Resolvers;
-
-namespace MediaBrowser.Server.Implementations.Library.Resolvers
-{
- /// <summary>
- /// Class ItemResolver
- /// </summary>
- /// <typeparam name="T"></typeparam>
- public abstract class ItemResolver<T> : IItemResolver
- where T : BaseItem, new()
- {
- /// <summary>
- /// Resolves the specified args.
- /// </summary>
- /// <param name="args">The args.</param>
- /// <returns>`0.</returns>
- protected virtual T Resolve(ItemResolveArgs args)
- {
- return null;
- }
-
- /// <summary>
- /// Gets the priority.
- /// </summary>
- /// <value>The priority.</value>
- public virtual ResolverPriority Priority
- {
- get
- {
- return ResolverPriority.First;
- }
- }
-
- /// <summary>
- /// Sets initial values on the newly resolved item
- /// </summary>
- /// <param name="item">The item.</param>
- /// <param name="args">The args.</param>
- protected virtual void SetInitialItemValues(T item, ItemResolveArgs args)
- {
- }
-
- /// <summary>
- /// Resolves the path.
- /// </summary>
- /// <param name="args">The args.</param>
- /// <returns>BaseItem.</returns>
- BaseItem IItemResolver.ResolvePath(ItemResolveArgs args)
- {
- var item = Resolve(args);
-
- if (item != null)
- {
- SetInitialItemValues(item, args);
- }
-
- return item;
- }
- }
-}
diff --git a/MediaBrowser.Server.Implementations/Library/Resolvers/Movies/BoxSetResolver.cs b/MediaBrowser.Server.Implementations/Library/Resolvers/Movies/BoxSetResolver.cs
deleted file mode 100644
index e3447afc9..000000000
--- a/MediaBrowser.Server.Implementations/Library/Resolvers/Movies/BoxSetResolver.cs
+++ /dev/null
@@ -1,77 +0,0 @@
-using MediaBrowser.Controller.Entities;
-using MediaBrowser.Controller.Entities.Movies;
-using MediaBrowser.Controller.Library;
-using MediaBrowser.Model.Entities;
-using System;
-using System.IO;
-
-namespace MediaBrowser.Server.Implementations.Library.Resolvers.Movies
-{
- /// <summary>
- /// Class BoxSetResolver
- /// </summary>
- public class BoxSetResolver : FolderResolver<BoxSet>
- {
- /// <summary>
- /// Resolves the specified args.
- /// </summary>
- /// <param name="args">The args.</param>
- /// <returns>BoxSet.</returns>
- protected override BoxSet Resolve(ItemResolveArgs args)
- {
- // It's a boxset if all of the following conditions are met:
- // Is a Directory
- // Contains [boxset] in the path
- if (args.IsDirectory)
- {
- var filename = Path.GetFileName(args.Path);
-
- if (string.IsNullOrEmpty(filename))
- {
- return null;
- }
-
- if (filename.IndexOf("[boxset]", StringComparison.OrdinalIgnoreCase) != -1 ||
- args.ContainsFileSystemEntryByName("collection.xml"))
- {
- return new BoxSet
- {
- Path = args.Path,
- Name = ResolverHelper.StripBrackets(Path.GetFileName(args.Path))
- };
- }
- }
-
- return null;
- }
-
- /// <summary>
- /// Sets the initial item values.
- /// </summary>
- /// <param name="item">The item.</param>
- /// <param name="args">The args.</param>
- protected override void SetInitialItemValues(BoxSet item, ItemResolveArgs args)
- {
- base.SetInitialItemValues(item, args);
-
- SetProviderIdFromPath(item);
- }
-
- /// <summary>
- /// Sets the provider id from path.
- /// </summary>
- /// <param name="item">The item.</param>
- private void SetProviderIdFromPath(BaseItem item)
- {
- //we need to only look at the name of this actual item (not parents)
- var justName = Path.GetFileName(item.Path);
-
- var id = justName.GetAttributeValue("tmdbid");
-
- if (!string.IsNullOrEmpty(id))
- {
- item.SetProviderId(MetadataProviders.Tmdb, id);
- }
- }
- }
-}
diff --git a/MediaBrowser.Server.Implementations/Library/Resolvers/Movies/MovieResolver.cs b/MediaBrowser.Server.Implementations/Library/Resolvers/Movies/MovieResolver.cs
deleted file mode 100644
index bb1d57688..000000000
--- a/MediaBrowser.Server.Implementations/Library/Resolvers/Movies/MovieResolver.cs
+++ /dev/null
@@ -1,541 +0,0 @@
-using MediaBrowser.Controller.Entities;
-using MediaBrowser.Controller.Entities.Movies;
-using MediaBrowser.Controller.Entities.TV;
-using MediaBrowser.Controller.Library;
-using MediaBrowser.Controller.Providers;
-using MediaBrowser.Controller.Resolvers;
-using MediaBrowser.Model.Entities;
-using MediaBrowser.Model.Extensions;
-using MediaBrowser.Naming.Video;
-using MediaBrowser.Server.Implementations.Logging;
-using System;
-using System.Collections.Generic;
-using System.IO;
-using System.Linq;
-using MediaBrowser.Common.IO;
-using MediaBrowser.Controller.IO;
-using MediaBrowser.Model.IO;
-
-namespace MediaBrowser.Server.Implementations.Library.Resolvers.Movies
-{
- /// <summary>
- /// Class MovieResolver
- /// </summary>
- public class MovieResolver : BaseVideoResolver<Video>, IMultiItemResolver
- {
- public MovieResolver(ILibraryManager libraryManager)
- : base(libraryManager)
- {
- }
-
- /// <summary>
- /// Gets the priority.
- /// </summary>
- /// <value>The priority.</value>
- public override ResolverPriority Priority
- {
- get
- {
- // Give plugins a chance to catch iso's first
- // Also since we have to loop through child files looking for videos,
- // see if we can avoid some of that by letting other resolvers claim folders first
- // Also run after series resolver
- return ResolverPriority.Third;
- }
- }
-
- public MultiItemResolverResult ResolveMultiple(Folder parent,
- List<FileSystemMetadata> files,
- string collectionType,
- IDirectoryService directoryService)
- {
- var result = ResolveMultipleInternal(parent, files, collectionType, directoryService);
-
- if (result != null)
- {
- foreach (var item in result.Items)
- {
- SetInitialItemValues((Video)item, null);
- }
- }
-
- return result;
- }
-
- private MultiItemResolverResult ResolveMultipleInternal(Folder parent,
- List<FileSystemMetadata> files,
- string collectionType,
- IDirectoryService directoryService)
- {
- if (IsInvalid(parent, collectionType))
- {
- return null;
- }
-
- if (string.Equals(collectionType, CollectionType.MusicVideos, StringComparison.OrdinalIgnoreCase))
- {
- return ResolveVideos<MusicVideo>(parent, files, directoryService, false);
- }
-
- if (string.Equals(collectionType, CollectionType.HomeVideos, StringComparison.OrdinalIgnoreCase) ||
- string.Equals(collectionType, CollectionType.Photos, StringComparison.OrdinalIgnoreCase))
- {
- return ResolveVideos<Video>(parent, files, directoryService, false);
- }
-
- if (string.IsNullOrEmpty(collectionType))
- {
- // Owned items should just use the plain video type
- if (parent == null)
- {
- return ResolveVideos<Video>(parent, files, directoryService, false);
- }
-
- if (parent is Series || parent.GetParents().OfType<Series>().Any())
- {
- return null;
- }
-
- return ResolveVideos<Movie>(parent, files, directoryService, false);
- }
-
- if (string.Equals(collectionType, CollectionType.Movies, StringComparison.OrdinalIgnoreCase))
- {
- return ResolveVideos<Movie>(parent, files, directoryService, true);
- }
-
- return null;
- }
-
- private MultiItemResolverResult ResolveVideos<T>(Folder parent, IEnumerable<FileSystemMetadata> fileSystemEntries, IDirectoryService directoryService, bool suppportMultiEditions)
- where T : Video, new()
- {
- var files = new List<FileSystemMetadata>();
- var videos = new List<BaseItem>();
- var leftOver = new List<FileSystemMetadata>();
-
- // Loop through each child file/folder and see if we find a video
- foreach (var child in fileSystemEntries)
- {
- if (child.IsDirectory)
- {
- leftOver.Add(child);
- }
- else if (IsIgnored(child.Name))
- {
-
- }
- else
- {
- files.Add(child);
- }
- }
-
- var namingOptions = ((LibraryManager)LibraryManager).GetNamingOptions();
-
- var resolver = new VideoListResolver(namingOptions, new PatternsLogger());
- var resolverResult = resolver.Resolve(files, suppportMultiEditions).ToList();
-
- var result = new MultiItemResolverResult
- {
- ExtraFiles = leftOver,
- Items = videos
- };
-
- var isInMixedFolder = resolverResult.Count > 1;
-
- foreach (var video in resolverResult)
- {
- var firstVideo = video.Files.First();
-
- var videoItem = new T
- {
- Path = video.Files[0].Path,
- IsInMixedFolder = isInMixedFolder,
- ProductionYear = video.Year,
- Name = video.Name,
- AdditionalParts = video.Files.Skip(1).Select(i => i.Path).ToList(),
- LocalAlternateVersions = video.AlternateVersions.Select(i => i.Path).ToList()
- };
-
- SetVideoType(videoItem, firstVideo);
- Set3DFormat(videoItem, firstVideo);
-
- result.Items.Add(videoItem);
- }
-
- result.ExtraFiles.AddRange(files.Where(i => !ContainsFile(resolverResult, i)));
-
- return result;
- }
-
- private bool ContainsFile(List<VideoInfo> result, FileSystemMetadata file)
- {
- return result.Any(i => ContainsFile(i, file));
- }
-
- private bool ContainsFile(VideoInfo result, FileSystemMetadata file)
- {
- return result.Files.Any(i => ContainsFile(i, file)) ||
- result.AlternateVersions.Any(i => ContainsFile(i, file)) ||
- result.Extras.Any(i => ContainsFile(i, file));
- }
-
- private bool ContainsFile(VideoFileInfo result, FileSystemMetadata file)
- {
- return string.Equals(result.Path, file.FullName, StringComparison.OrdinalIgnoreCase);
- }
-
- /// <summary>
- /// Resolves the specified args.
- /// </summary>
- /// <param name="args">The args.</param>
- /// <returns>Video.</returns>
- protected override Video Resolve(ItemResolveArgs args)
- {
- var collectionType = args.GetCollectionType();
-
- if (IsInvalid(args.Parent, collectionType))
- {
- return null;
- }
-
- // Find movies with their own folders
- if (args.IsDirectory)
- {
- var files = args.FileSystemChildren
- .Where(i => !LibraryManager.IgnoreFile(i, args.Parent))
- .ToList();
-
- if (string.Equals(collectionType, CollectionType.MusicVideos, StringComparison.OrdinalIgnoreCase))
- {
- return FindMovie<MusicVideo>(args.Path, args.Parent, files, args.DirectoryService, collectionType, false);
- }
-
- if (string.Equals(collectionType, CollectionType.HomeVideos, StringComparison.OrdinalIgnoreCase))
- {
- return FindMovie<Video>(args.Path, args.Parent, files, args.DirectoryService, collectionType, false);
- }
-
- if (string.IsNullOrEmpty(collectionType))
- {
- // Owned items will be caught by the plain video resolver
- if (args.Parent == null)
- {
- //return FindMovie<Video>(args.Path, args.Parent, files, args.DirectoryService, collectionType);
- return null;
- }
-
- if (args.HasParent<Series>())
- {
- return null;
- }
-
- {
- return FindMovie<Movie>(args.Path, args.Parent, files, args.DirectoryService, collectionType, true);
- }
- }
-
- if (string.Equals(collectionType, CollectionType.Movies, StringComparison.OrdinalIgnoreCase))
- {
- return FindMovie<Movie>(args.Path, args.Parent, files, args.DirectoryService, collectionType, true);
- }
-
- return null;
- }
-
- // Owned items will be caught by the plain video resolver
- if (args.Parent == null)
- {
- return null;
- }
-
- Video item = null;
-
- if (string.Equals(collectionType, CollectionType.MusicVideos, StringComparison.OrdinalIgnoreCase))
- {
- item = ResolveVideo<MusicVideo>(args, false);
- }
-
- // To find a movie file, the collection type must be movies or boxsets
- else if (string.Equals(collectionType, CollectionType.Movies, StringComparison.OrdinalIgnoreCase))
- {
- item = ResolveVideo<Movie>(args, true);
- }
-
- else if (string.Equals(collectionType, CollectionType.HomeVideos, StringComparison.OrdinalIgnoreCase) ||
- string.Equals(collectionType, CollectionType.Photos, StringComparison.OrdinalIgnoreCase))
- {
- item = ResolveVideo<Video>(args, false);
- }
- else if (string.IsNullOrEmpty(collectionType))
- {
- if (args.HasParent<Series>())
- {
- return null;
- }
-
- item = ResolveVideo<Video>(args, false);
- }
-
- if (item != null)
- {
- item.IsInMixedFolder = true;
- }
-
- return item;
- }
-
- private bool IsIgnored(string filename)
- {
- // Ignore samples
- var sampleFilename = " " + filename.Replace(".", " ", StringComparison.OrdinalIgnoreCase)
- .Replace("-", " ", StringComparison.OrdinalIgnoreCase)
- .Replace("_", " ", StringComparison.OrdinalIgnoreCase)
- .Replace("!", " ", StringComparison.OrdinalIgnoreCase);
-
- if (sampleFilename.IndexOf(" sample ", StringComparison.OrdinalIgnoreCase) != -1)
- {
- return true;
- }
-
- return false;
- }
-
- /// <summary>
- /// Sets the initial item values.
- /// </summary>
- /// <param name="item">The item.</param>
- /// <param name="args">The args.</param>
- protected override void SetInitialItemValues(Video item, ItemResolveArgs args)
- {
- base.SetInitialItemValues(item, args);
-
- SetProviderIdsFromPath(item);
- }
-
- /// <summary>
- /// Sets the provider id from path.
- /// </summary>
- /// <param name="item">The item.</param>
- private void SetProviderIdsFromPath(Video item)
- {
- if (item is Movie || item is MusicVideo)
- {
- //we need to only look at the name of this actual item (not parents)
- var justName = item.IsInMixedFolder ? Path.GetFileName(item.Path) : Path.GetFileName(item.ContainingFolderPath);
-
- if (!string.IsNullOrWhiteSpace(justName))
- {
- // check for tmdb id
- var tmdbid = justName.GetAttributeValue("tmdbid");
-
- if (!string.IsNullOrWhiteSpace(tmdbid))
- {
- item.SetProviderId(MetadataProviders.Tmdb, tmdbid);
- }
- }
-
- if (!string.IsNullOrWhiteSpace(item.Path))
- {
- // check for imdb id - we use full media path, as we can assume, that this will match in any use case (wither id in parent dir or in file name)
- var imdbid = item.Path.GetAttributeValue("imdbid");
-
- if (!string.IsNullOrWhiteSpace(imdbid))
- {
- item.SetProviderId(MetadataProviders.Imdb, imdbid);
- }
- }
- }
- }
-
- /// <summary>
- /// Finds a movie based on a child file system entries
- /// </summary>
- /// <typeparam name="T"></typeparam>
- /// <returns>Movie.</returns>
- private T FindMovie<T>(string path, Folder parent, List<FileSystemMetadata> fileSystemEntries, IDirectoryService directoryService, string collectionType, bool allowFilesAsFolders)
- where T : Video, new()
- {
- var multiDiscFolders = new List<FileSystemMetadata>();
-
- // Search for a folder rip
- foreach (var child in fileSystemEntries)
- {
- var filename = child.Name;
-
- if (child.IsDirectory)
- {
- if (IsDvdDirectory(filename))
- {
- var movie = new T
- {
- Path = path,
- VideoType = VideoType.Dvd
- };
- Set3DFormat(movie);
- return movie;
- }
- if (IsBluRayDirectory(filename))
- {
- var movie = new T
- {
- Path = path,
- VideoType = VideoType.BluRay
- };
- Set3DFormat(movie);
- return movie;
- }
-
- multiDiscFolders.Add(child);
- }
- else if (IsDvdFile(filename))
- {
- var movie = new T
- {
- Path = path,
- VideoType = VideoType.Dvd
- };
- Set3DFormat(movie);
- return movie;
- }
- }
-
- if (allowFilesAsFolders)
- {
- // TODO: Allow GetMultiDiscMovie in here
- var supportsMultiVersion = !string.Equals(collectionType, CollectionType.HomeVideos) &&
- !string.Equals(collectionType, CollectionType.Photos) &&
- !string.Equals(collectionType, CollectionType.MusicVideos);
-
- var result = ResolveVideos<T>(parent, fileSystemEntries, directoryService, supportsMultiVersion);
-
- if (result.Items.Count == 1)
- {
- var movie = (T)result.Items[0];
- movie.IsInMixedFolder = false;
- movie.Name = Path.GetFileName(movie.ContainingFolderPath);
- return movie;
- }
-
- if (result.Items.Count == 0 && multiDiscFolders.Count > 0)
- {
- return GetMultiDiscMovie<T>(multiDiscFolders, directoryService);
- }
- }
-
- return null;
- }
-
- /// <summary>
- /// Gets the multi disc movie.
- /// </summary>
- /// <typeparam name="T"></typeparam>
- /// <param name="multiDiscFolders">The folders.</param>
- /// <param name="directoryService">The directory service.</param>
- /// <returns>``0.</returns>
- private T GetMultiDiscMovie<T>(List<FileSystemMetadata> multiDiscFolders, IDirectoryService directoryService)
- where T : Video, new()
- {
- var videoTypes = new List<VideoType>();
-
- var folderPaths = multiDiscFolders.Select(i => i.FullName).Where(i =>
- {
- var subFileEntries = directoryService.GetFileSystemEntries(i)
- .ToList();
-
- var subfolders = subFileEntries
- .Where(e => e.IsDirectory)
- .Select(d => d.Name)
- .ToList();
-
- if (subfolders.Any(IsDvdDirectory))
- {
- videoTypes.Add(VideoType.Dvd);
- return true;
- }
- if (subfolders.Any(IsBluRayDirectory))
- {
- videoTypes.Add(VideoType.BluRay);
- return true;
- }
-
- var subFiles = subFileEntries
- .Where(e => !e.IsDirectory)
- .Select(d => d.Name);
-
- if (subFiles.Any(IsDvdFile))
- {
- videoTypes.Add(VideoType.Dvd);
- return true;
- }
-
- return false;
-
- }).OrderBy(i => i).ToList();
-
- // If different video types were found, don't allow this
- if (videoTypes.Distinct().Count() > 1)
- {
- return null;
- }
-
- if (folderPaths.Count == 0)
- {
- return null;
- }
-
- var namingOptions = ((LibraryManager)LibraryManager).GetNamingOptions();
- var resolver = new StackResolver(namingOptions, new PatternsLogger());
-
- var result = resolver.ResolveDirectories(folderPaths);
-
- if (result.Stacks.Count != 1)
- {
- return null;
- }
-
- var returnVideo = new T
- {
- Path = folderPaths[0],
-
- AdditionalParts = folderPaths.Skip(1).ToList(),
-
- VideoType = videoTypes[0],
-
- Name = result.Stacks[0].Name
- };
-
- SetIsoType(returnVideo);
-
- return returnVideo;
- }
-
- private bool IsInvalid(Folder parent, string collectionType)
- {
- if (parent != null)
- {
- if (parent.IsRoot)
- {
- return true;
- }
- }
-
- var validCollectionTypes = new[]
- {
- CollectionType.Movies,
- CollectionType.HomeVideos,
- CollectionType.MusicVideos,
- CollectionType.Movies,
- CollectionType.Photos
- };
-
- if (string.IsNullOrWhiteSpace(collectionType))
- {
- return false;
- }
-
- return !validCollectionTypes.Contains(collectionType, StringComparer.OrdinalIgnoreCase);
- }
- }
-}
diff --git a/MediaBrowser.Server.Implementations/Library/Resolvers/PhotoAlbumResolver.cs b/MediaBrowser.Server.Implementations/Library/Resolvers/PhotoAlbumResolver.cs
deleted file mode 100644
index 957fafb92..000000000
--- a/MediaBrowser.Server.Implementations/Library/Resolvers/PhotoAlbumResolver.cs
+++ /dev/null
@@ -1,56 +0,0 @@
-using MediaBrowser.Controller.Drawing;
-using MediaBrowser.Controller.Entities;
-using MediaBrowser.Controller.Library;
-using MediaBrowser.Controller.Resolvers;
-using MediaBrowser.Model.Entities;
-using System;
-using System.IO;
-using System.Linq;
-
-namespace MediaBrowser.Server.Implementations.Library.Resolvers
-{
- public class PhotoAlbumResolver : FolderResolver<PhotoAlbum>
- {
- private readonly IImageProcessor _imageProcessor;
- public PhotoAlbumResolver(IImageProcessor imageProcessor)
- {
- _imageProcessor = imageProcessor;
- }
-
- /// <summary>
- /// Resolves the specified args.
- /// </summary>
- /// <param name="args">The args.</param>
- /// <returns>Trailer.</returns>
- protected override PhotoAlbum Resolve(ItemResolveArgs args)
- {
- // Must be an image file within a photo collection
- if (args.IsDirectory && string.Equals(args.GetCollectionType(), CollectionType.Photos, StringComparison.OrdinalIgnoreCase))
- {
- if (HasPhotos(args))
- {
- return new PhotoAlbum
- {
- Path = args.Path
- };
- }
- }
-
- return null;
- }
-
- private bool HasPhotos(ItemResolveArgs args)
- {
- return args.FileSystemChildren.Any(i => (!i.IsDirectory) && PhotoResolver.IsImageFile(i.FullName, _imageProcessor));
- }
-
- public override ResolverPriority Priority
- {
- get
- {
- // Behind special folder resolver
- return ResolverPriority.Second;
- }
- }
- }
-}
diff --git a/MediaBrowser.Server.Implementations/Library/Resolvers/PhotoResolver.cs b/MediaBrowser.Server.Implementations/Library/Resolvers/PhotoResolver.cs
deleted file mode 100644
index 549ad522e..000000000
--- a/MediaBrowser.Server.Implementations/Library/Resolvers/PhotoResolver.cs
+++ /dev/null
@@ -1,103 +0,0 @@
-using MediaBrowser.Controller.Drawing;
-using MediaBrowser.Controller.Entities;
-using MediaBrowser.Controller.Library;
-using MediaBrowser.Model.Entities;
-using System;
-using System.IO;
-using System.Linq;
-using MediaBrowser.Common.IO;
-using MediaBrowser.Model.IO;
-using MediaBrowser.Controller.Configuration;
-using MediaBrowser.Controller.IO;
-using MediaBrowser.Model.Configuration;
-
-namespace MediaBrowser.Server.Implementations.Library.Resolvers
-{
- public class PhotoResolver : ItemResolver<Photo>
- {
- private readonly IImageProcessor _imageProcessor;
- private readonly ILibraryManager _libraryManager;
-
- public PhotoResolver(IImageProcessor imageProcessor, ILibraryManager libraryManager)
- {
- _imageProcessor = imageProcessor;
- _libraryManager = libraryManager;
- }
-
- /// <summary>
- /// Resolves the specified args.
- /// </summary>
- /// <param name="args">The args.</param>
- /// <returns>Trailer.</returns>
- protected override Photo Resolve(ItemResolveArgs args)
- {
- if (!args.IsDirectory)
- {
- // Must be an image file within a photo collection
- var collectionType = args.GetCollectionType();
-
-
- if (string.Equals(collectionType, CollectionType.Photos, StringComparison.OrdinalIgnoreCase) ||
- (string.Equals(collectionType, CollectionType.HomeVideos, StringComparison.OrdinalIgnoreCase) && args.GetLibraryOptions().EnablePhotos))
- {
- if (IsImageFile(args.Path, _imageProcessor))
- {
- var filename = Path.GetFileNameWithoutExtension(args.Path);
-
- // Make sure the image doesn't belong to a video file
- if (args.DirectoryService.GetFiles(Path.GetDirectoryName(args.Path)).Any(i => IsOwnedByMedia(args.GetLibraryOptions(), i, filename)))
- {
- return null;
- }
-
- return new Photo
- {
- Path = args.Path
- };
- }
- }
- }
-
- return null;
- }
-
- private bool IsOwnedByMedia(LibraryOptions libraryOptions, FileSystemMetadata file, string imageFilename)
- {
- if (_libraryManager.IsVideoFile(file.FullName, libraryOptions) && imageFilename.StartsWith(Path.GetFileNameWithoutExtension(file.Name), StringComparison.OrdinalIgnoreCase))
- {
- return true;
- }
-
- return false;
- }
-
- private static readonly string[] IgnoreFiles =
- {
- "folder",
- "thumb",
- "landscape",
- "fanart",
- "backdrop",
- "poster",
- "cover"
- };
-
- internal static bool IsImageFile(string path, IImageProcessor imageProcessor)
- {
- var filename = Path.GetFileNameWithoutExtension(path) ?? string.Empty;
-
- if (IgnoreFiles.Contains(filename, StringComparer.OrdinalIgnoreCase))
- {
- return false;
- }
-
- if (IgnoreFiles.Any(i => filename.IndexOf(i, StringComparison.OrdinalIgnoreCase) != -1))
- {
- return false;
- }
-
- return imageProcessor.SupportedInputFormats.Contains((Path.GetExtension(path) ?? string.Empty).TrimStart('.'), StringComparer.OrdinalIgnoreCase);
- }
-
- }
-}
diff --git a/MediaBrowser.Server.Implementations/Library/Resolvers/PlaylistResolver.cs b/MediaBrowser.Server.Implementations/Library/Resolvers/PlaylistResolver.cs
deleted file mode 100644
index a95739f22..000000000
--- a/MediaBrowser.Server.Implementations/Library/Resolvers/PlaylistResolver.cs
+++ /dev/null
@@ -1,42 +0,0 @@
-using MediaBrowser.Controller.Library;
-using MediaBrowser.Controller.Playlists;
-using System;
-using System.IO;
-
-namespace MediaBrowser.Server.Implementations.Library.Resolvers
-{
- public class PlaylistResolver : FolderResolver<Playlist>
- {
- /// <summary>
- /// Resolves the specified args.
- /// </summary>
- /// <param name="args">The args.</param>
- /// <returns>BoxSet.</returns>
- protected override Playlist Resolve(ItemResolveArgs args)
- {
- // It's a boxset if all of the following conditions are met:
- // Is a Directory
- // Contains [playlist] in the path
- if (args.IsDirectory)
- {
- var filename = Path.GetFileName(args.Path);
-
- if (string.IsNullOrEmpty(filename))
- {
- return null;
- }
-
- if (filename.IndexOf("[playlist]", StringComparison.OrdinalIgnoreCase) != -1)
- {
- return new Playlist
- {
- Path = args.Path,
- Name = ResolverHelper.StripBrackets(Path.GetFileName(args.Path))
- };
- }
- }
-
- return null;
- }
- }
-}
diff --git a/MediaBrowser.Server.Implementations/Library/Resolvers/SpecialFolderResolver.cs b/MediaBrowser.Server.Implementations/Library/Resolvers/SpecialFolderResolver.cs
deleted file mode 100644
index 7a6198a00..000000000
--- a/MediaBrowser.Server.Implementations/Library/Resolvers/SpecialFolderResolver.cs
+++ /dev/null
@@ -1,85 +0,0 @@
-using MediaBrowser.Controller;
-using MediaBrowser.Controller.Entities;
-using MediaBrowser.Controller.Library;
-using MediaBrowser.Controller.Resolvers;
-using System;
-using System.IO;
-using System.Linq;
-using MediaBrowser.Common.IO;
-using MediaBrowser.Controller.IO;
-using MediaBrowser.Model.IO;
-
-namespace MediaBrowser.Server.Implementations.Library.Resolvers
-{
- class SpecialFolderResolver : FolderResolver<Folder>
- {
- private readonly IFileSystem _fileSystem;
- private readonly IServerApplicationPaths _appPaths;
-
- public SpecialFolderResolver(IFileSystem fileSystem, IServerApplicationPaths appPaths)
- {
- _fileSystem = fileSystem;
- _appPaths = appPaths;
- }
-
- /// <summary>
- /// Gets the priority.
- /// </summary>
- /// <value>The priority.</value>
- public override ResolverPriority Priority
- {
- get { return ResolverPriority.First; }
- }
-
- /// <summary>
- /// Resolves the specified args.
- /// </summary>
- /// <param name="args">The args.</param>
- /// <returns>Folder.</returns>
- protected override Folder Resolve(ItemResolveArgs args)
- {
- if (args.IsDirectory)
- {
- if (args.IsPhysicalRoot)
- {
- return new AggregateFolder();
- }
- if (string.Equals(args.Path, _appPaths.DefaultUserViewsPath, StringComparison.OrdinalIgnoreCase))
- {
- return new UserRootFolder(); //if we got here and still a root - must be user root
- }
- if (args.IsVf)
- {
- return new CollectionFolder
- {
- CollectionType = GetCollectionType(args),
- PhysicalLocationsList = args.PhysicalLocations.ToList()
- };
- }
- }
-
- return null;
- }
-
- private string GetCollectionType(ItemResolveArgs args)
- {
- return args.FileSystemChildren
- .Where(i =>
- {
-
- try
- {
- return !i.IsDirectory &&
- string.Equals(".collection", i.Extension, StringComparison.OrdinalIgnoreCase);
- }
- catch (IOException)
- {
- return false;
- }
-
- })
- .Select(i => _fileSystem.GetFileNameWithoutExtension(i))
- .FirstOrDefault();
- }
- }
-}
diff --git a/MediaBrowser.Server.Implementations/Library/Resolvers/TV/EpisodeResolver.cs b/MediaBrowser.Server.Implementations/Library/Resolvers/TV/EpisodeResolver.cs
deleted file mode 100644
index 6edc4a009..000000000
--- a/MediaBrowser.Server.Implementations/Library/Resolvers/TV/EpisodeResolver.cs
+++ /dev/null
@@ -1,75 +0,0 @@
-using System;
-using MediaBrowser.Controller.Entities.TV;
-using MediaBrowser.Controller.Library;
-using System.Linq;
-using MediaBrowser.Model.Entities;
-
-namespace MediaBrowser.Server.Implementations.Library.Resolvers.TV
-{
- /// <summary>
- /// Class EpisodeResolver
- /// </summary>
- public class EpisodeResolver : BaseVideoResolver<Episode>
- {
- public EpisodeResolver(ILibraryManager libraryManager) : base(libraryManager)
- {
- }
-
- /// <summary>
- /// Resolves the specified args.
- /// </summary>
- /// <param name="args">The args.</param>
- /// <returns>Episode.</returns>
- protected override Episode Resolve(ItemResolveArgs args)
- {
- var parent = args.Parent;
-
- if (parent == null)
- {
- return null;
- }
-
- var season = parent as Season;
- // Just in case the user decided to nest episodes.
- // Not officially supported but in some cases we can handle it.
- if (season == null)
- {
- season = parent.GetParents().OfType<Season>().FirstOrDefault();
- }
-
- // If the parent is a Season or Series, then this is an Episode if the VideoResolver returns something
- // Also handle flat tv folders
- if (season != null ||
- string.Equals(args.GetCollectionType(), CollectionType.TvShows, StringComparison.OrdinalIgnoreCase) ||
- args.HasParent<Series>())
- {
- var episode = ResolveVideo<Episode>(args, false);
-
- if (episode != null)
- {
- var series = parent as Series;
- if (series == null)
- {
- series = parent.GetParents().OfType<Series>().FirstOrDefault();
- }
-
- if (series != null)
- {
- episode.SeriesId = series.Id;
- episode.SeriesName = series.Name;
- episode.SeriesSortName = series.SortName;
- }
- if (season != null)
- {
- episode.SeasonId = season.Id;
- episode.SeasonName = season.Name;
- }
- }
-
- return episode;
- }
-
- return null;
- }
- }
-}
diff --git a/MediaBrowser.Server.Implementations/Library/Resolvers/TV/SeasonResolver.cs b/MediaBrowser.Server.Implementations/Library/Resolvers/TV/SeasonResolver.cs
deleted file mode 100644
index fc4929748..000000000
--- a/MediaBrowser.Server.Implementations/Library/Resolvers/TV/SeasonResolver.cs
+++ /dev/null
@@ -1,62 +0,0 @@
-using MediaBrowser.Controller.Configuration;
-using MediaBrowser.Controller.Entities.TV;
-using MediaBrowser.Controller.Library;
-using MediaBrowser.Naming.Common;
-using MediaBrowser.Naming.TV;
-
-namespace MediaBrowser.Server.Implementations.Library.Resolvers.TV
-{
- /// <summary>
- /// Class SeasonResolver
- /// </summary>
- public class SeasonResolver : FolderResolver<Season>
- {
- /// <summary>
- /// The _config
- /// </summary>
- private readonly IServerConfigurationManager _config;
-
- private readonly ILibraryManager _libraryManager;
-
- /// <summary>
- /// Initializes a new instance of the <see cref="SeasonResolver"/> class.
- /// </summary>
- /// <param name="config">The config.</param>
- public SeasonResolver(IServerConfigurationManager config, ILibraryManager libraryManager)
- {
- _config = config;
- _libraryManager = libraryManager;
- }
-
- /// <summary>
- /// Resolves the specified args.
- /// </summary>
- /// <param name="args">The args.</param>
- /// <returns>Season.</returns>
- protected override Season Resolve(ItemResolveArgs args)
- {
- if (args.Parent is Series && args.IsDirectory)
- {
- var namingOptions = ((LibraryManager)_libraryManager).GetNamingOptions();
- var series = ((Series)args.Parent);
-
- var season = new Season
- {
- IndexNumber = new SeasonPathParser(namingOptions, new RegexProvider()).Parse(args.Path, true, true).SeasonNumber,
- SeriesId = series.Id,
- SeriesSortName = series.SortName,
- SeriesName = series.Name
- };
-
- if (season.IndexNumber.HasValue && season.IndexNumber.Value == 0)
- {
- season.Name = _config.Configuration.SeasonZeroDisplayName;
- }
-
- return season;
- }
-
- return null;
- }
- }
-}
diff --git a/MediaBrowser.Server.Implementations/Library/Resolvers/TV/SeriesResolver.cs b/MediaBrowser.Server.Implementations/Library/Resolvers/TV/SeriesResolver.cs
deleted file mode 100644
index 83566e2c1..000000000
--- a/MediaBrowser.Server.Implementations/Library/Resolvers/TV/SeriesResolver.cs
+++ /dev/null
@@ -1,251 +0,0 @@
-using MediaBrowser.Controller.Entities.TV;
-using MediaBrowser.Controller.Library;
-using MediaBrowser.Controller.Providers;
-using MediaBrowser.Controller.Resolvers;
-using MediaBrowser.Model.Entities;
-using MediaBrowser.Model.Logging;
-using MediaBrowser.Naming.Common;
-using MediaBrowser.Naming.TV;
-using MediaBrowser.Server.Implementations.Logging;
-using System;
-using System.Collections.Generic;
-using System.IO;
-using System.Linq;
-using MediaBrowser.Common.IO;
-using MediaBrowser.Model.IO;
-using MediaBrowser.Controller.Configuration;
-using MediaBrowser.Controller.IO;
-using MediaBrowser.Model.Configuration;
-
-namespace MediaBrowser.Server.Implementations.Library.Resolvers.TV
-{
- /// <summary>
- /// Class SeriesResolver
- /// </summary>
- public class SeriesResolver : FolderResolver<Series>
- {
- private readonly IFileSystem _fileSystem;
- private readonly ILogger _logger;
- private readonly ILibraryManager _libraryManager;
-
- public SeriesResolver(IFileSystem fileSystem, ILogger logger, ILibraryManager libraryManager)
- {
- _fileSystem = fileSystem;
- _logger = logger;
- _libraryManager = libraryManager;
- }
-
- /// <summary>
- /// Gets the priority.
- /// </summary>
- /// <value>The priority.</value>
- public override ResolverPriority Priority
- {
- get
- {
- return ResolverPriority.Second;
- }
- }
-
- /// <summary>
- /// Resolves the specified args.
- /// </summary>
- /// <param name="args">The args.</param>
- /// <returns>Series.</returns>
- protected override Series Resolve(ItemResolveArgs args)
- {
- if (args.IsDirectory)
- {
- if (args.HasParent<Series>() || args.HasParent<Season>())
- {
- return null;
- }
-
- var collectionType = args.GetCollectionType();
- if (string.Equals(collectionType, CollectionType.TvShows, StringComparison.OrdinalIgnoreCase))
- {
- //if (args.ContainsFileSystemEntryByName("tvshow.nfo"))
- //{
- // return new Series
- // {
- // Path = args.Path,
- // Name = Path.GetFileName(args.Path)
- // };
- //}
-
- var configuredContentType = _libraryManager.GetConfiguredContentType(args.Path);
- if (!string.Equals(configuredContentType, CollectionType.TvShows, StringComparison.OrdinalIgnoreCase))
- {
- return new Series
- {
- Path = args.Path,
- Name = Path.GetFileName(args.Path)
- };
- }
- }
- else if (string.IsNullOrWhiteSpace(collectionType))
- {
- if (args.ContainsFileSystemEntryByName("tvshow.nfo"))
- {
- if (args.Parent.IsRoot)
- {
- // For now, return null, but if we want to allow this in the future then add some additional checks to guard against a misplaced tvshow.nfo
- return null;
- }
-
- return new Series
- {
- Path = args.Path,
- Name = Path.GetFileName(args.Path)
- };
- }
-
- if (args.Parent.IsRoot)
- {
- return null;
- }
-
- if (IsSeriesFolder(args.Path, args.FileSystemChildren, args.DirectoryService, _fileSystem, _logger, _libraryManager, args.GetLibraryOptions(), false))
- {
- return new Series
- {
- Path = args.Path,
- Name = Path.GetFileName(args.Path)
- };
- }
- }
- }
-
- return null;
- }
-
- public static bool IsSeriesFolder(string path,
- IEnumerable<FileSystemMetadata> fileSystemChildren,
- IDirectoryService directoryService,
- IFileSystem fileSystem,
- ILogger logger,
- ILibraryManager libraryManager,
- LibraryOptions libraryOptions,
- bool isTvContentType)
- {
- foreach (var child in fileSystemChildren)
- {
- //if ((attributes & FileAttributes.Hidden) == FileAttributes.Hidden)
- //{
- // //logger.Debug("Igoring series file or folder marked hidden: {0}", child.FullName);
- // continue;
- //}
-
- // Can't enforce this because files saved by Bitcasa are always marked System
- //if ((attributes & FileAttributes.System) == FileAttributes.System)
- //{
- // logger.Debug("Igoring series subfolder marked system: {0}", child.FullName);
- // continue;
- //}
-
- if (child.IsDirectory)
- {
- if (IsSeasonFolder(child.FullName, isTvContentType, libraryManager))
- {
- //logger.Debug("{0} is a series because of season folder {1}.", path, child.FullName);
- return true;
- }
- }
- else
- {
- string fullName = child.FullName;
- if (libraryManager.IsVideoFile(fullName, libraryOptions))
- {
- if (isTvContentType)
- {
- return true;
- }
-
- var namingOptions = ((LibraryManager)libraryManager).GetNamingOptions();
-
- // In mixed folders we need to be conservative and avoid expressions that may result in false positives (e.g. movies with numbers in the title)
- if (!isTvContentType)
- {
- namingOptions.EpisodeExpressions = namingOptions.EpisodeExpressions
- .Where(i => i.IsNamed && !i.IsOptimistic)
- .ToList();
- }
-
- var episodeResolver = new Naming.TV.EpisodeResolver(namingOptions, new PatternsLogger());
- var episodeInfo = episodeResolver.Resolve(fullName, false, false);
- if (episodeInfo != null && episodeInfo.EpisodeNumber.HasValue)
- {
- return true;
- }
- }
- }
- }
-
- logger.Debug("{0} is not a series folder.", path);
- return false;
- }
-
- /// <summary>
- /// Determines whether [is place holder] [the specified path].
- /// </summary>
- /// <param name="path">The path.</param>
- /// <returns><c>true</c> if [is place holder] [the specified path]; otherwise, <c>false</c>.</returns>
- /// <exception cref="System.ArgumentNullException">path</exception>
- private static bool IsVideoPlaceHolder(string path)
- {
- if (string.IsNullOrEmpty(path))
- {
- throw new ArgumentNullException("path");
- }
-
- var extension = Path.GetExtension(path);
-
- return string.Equals(extension, ".disc", StringComparison.OrdinalIgnoreCase);
- }
-
- /// <summary>
- /// Determines whether [is season folder] [the specified path].
- /// </summary>
- /// <param name="path">The path.</param>
- /// <param name="isTvContentType">if set to <c>true</c> [is tv content type].</param>
- /// <param name="libraryManager">The library manager.</param>
- /// <returns><c>true</c> if [is season folder] [the specified path]; otherwise, <c>false</c>.</returns>
- private static bool IsSeasonFolder(string path, bool isTvContentType, ILibraryManager libraryManager)
- {
- var namingOptions = ((LibraryManager)libraryManager).GetNamingOptions();
-
- var seasonNumber = new SeasonPathParser(namingOptions, new RegexProvider()).Parse(path, isTvContentType, isTvContentType).SeasonNumber;
-
- return seasonNumber.HasValue;
- }
-
- /// <summary>
- /// Sets the initial item values.
- /// </summary>
- /// <param name="item">The item.</param>
- /// <param name="args">The args.</param>
- protected override void SetInitialItemValues(Series item, ItemResolveArgs args)
- {
- base.SetInitialItemValues(item, args);
-
- SetProviderIdFromPath(item, args.Path);
- }
-
- /// <summary>
- /// Sets the provider id from path.
- /// </summary>
- /// <param name="item">The item.</param>
- /// <param name="path">The path.</param>
- private void SetProviderIdFromPath(Series item, string path)
- {
- var justName = Path.GetFileName(path);
-
- var id = justName.GetAttributeValue("tvdbid");
-
- if (!string.IsNullOrEmpty(id))
- {
- item.SetProviderId(MetadataProviders.Tvdb, id);
- }
- }
- }
-}
diff --git a/MediaBrowser.Server.Implementations/Library/Resolvers/VideoResolver.cs b/MediaBrowser.Server.Implementations/Library/Resolvers/VideoResolver.cs
deleted file mode 100644
index c7f21cef1..000000000
--- a/MediaBrowser.Server.Implementations/Library/Resolvers/VideoResolver.cs
+++ /dev/null
@@ -1,45 +0,0 @@
-using MediaBrowser.Controller.Entities;
-using MediaBrowser.Controller.Library;
-using MediaBrowser.Controller.Resolvers;
-
-namespace MediaBrowser.Server.Implementations.Library.Resolvers
-{
- /// <summary>
- /// Resolves a Path into a Video
- /// </summary>
- public class VideoResolver : BaseVideoResolver<Video>
- {
- public VideoResolver(ILibraryManager libraryManager)
- : base(libraryManager)
- {
- }
-
- protected override Video Resolve(ItemResolveArgs args)
- {
- if (args.Parent != null)
- {
- // The movie resolver will handle this
- return null;
- }
-
- return base.Resolve(args);
- }
-
- /// <summary>
- /// Gets the priority.
- /// </summary>
- /// <value>The priority.</value>
- public override ResolverPriority Priority
- {
- get { return ResolverPriority.Last; }
- }
- }
-
- public class GenericVideoResolver<T> : BaseVideoResolver<T>
- where T : Video, new ()
- {
- public GenericVideoResolver(ILibraryManager libraryManager) : base(libraryManager)
- {
- }
- }
-}
diff --git a/MediaBrowser.Server.Implementations/Library/SearchEngine.cs b/MediaBrowser.Server.Implementations/Library/SearchEngine.cs
deleted file mode 100644
index c266fb191..000000000
--- a/MediaBrowser.Server.Implementations/Library/SearchEngine.cs
+++ /dev/null
@@ -1,280 +0,0 @@
-using MediaBrowser.Common.Extensions;
-using MediaBrowser.Controller.Entities;
-using MediaBrowser.Controller.Entities.Audio;
-using MediaBrowser.Controller.Entities.TV;
-using MediaBrowser.Controller.Library;
-using MediaBrowser.Model.Logging;
-using MediaBrowser.Model.Querying;
-using MediaBrowser.Model.Search;
-using System;
-using System.Collections.Generic;
-using System.Linq;
-using System.Threading.Tasks;
-using MediaBrowser.Controller.Extensions;
-using MediaBrowser.Model.Extensions;
-
-namespace MediaBrowser.Server.Implementations.Library
-{
- /// <summary>
- /// Class LuceneSearchEngine
- /// http://www.codeproject.com/Articles/320219/Lucene-Net-ultra-fast-search-for-MVC-or-WebForms
- /// </summary>
- public class SearchEngine : ISearchEngine
- {
- private readonly ILibraryManager _libraryManager;
- private readonly IUserManager _userManager;
- private readonly ILogger _logger;
-
- public SearchEngine(ILogManager logManager, ILibraryManager libraryManager, IUserManager userManager)
- {
- _libraryManager = libraryManager;
- _userManager = userManager;
-
- _logger = logManager.GetLogger("Lucene");
- }
-
- public async Task<QueryResult<SearchHintInfo>> GetSearchHints(SearchQuery query)
- {
- User user = null;
-
- if (string.IsNullOrWhiteSpace(query.UserId))
- {
- }
- else
- {
- user = _userManager.GetUserById(query.UserId);
- }
-
- var results = await GetSearchHints(query, user).ConfigureAwait(false);
-
- var searchResultArray = results.ToArray();
- results = searchResultArray;
-
- var count = searchResultArray.Length;
-
- if (query.StartIndex.HasValue)
- {
- results = results.Skip(query.StartIndex.Value);
- }
-
- if (query.Limit.HasValue)
- {
- results = results.Take(query.Limit.Value);
- }
-
- return new QueryResult<SearchHintInfo>
- {
- TotalRecordCount = count,
-
- Items = results.ToArray()
- };
- }
-
- private void AddIfMissing(List<string> list, string value)
- {
- if (!list.Contains(value, StringComparer.OrdinalIgnoreCase))
- {
- list.Add(value);
- }
- }
-
- /// <summary>
- /// Gets the search hints.
- /// </summary>
- /// <param name="query">The query.</param>
- /// <param name="user">The user.</param>
- /// <returns>IEnumerable{SearchHintResult}.</returns>
- /// <exception cref="System.ArgumentNullException">searchTerm</exception>
- private Task<IEnumerable<SearchHintInfo>> GetSearchHints(SearchQuery query, User user)
- {
- var searchTerm = query.SearchTerm;
-
- if (searchTerm != null)
- {
- searchTerm = searchTerm.Trim().RemoveDiacritics();
- }
-
- if (string.IsNullOrWhiteSpace(searchTerm))
- {
- throw new ArgumentNullException("searchTerm");
- }
-
- var terms = GetWords(searchTerm);
-
- var hints = new List<Tuple<BaseItem, string, int>>();
-
- var excludeItemTypes = new List<string>();
- var includeItemTypes = (query.IncludeItemTypes ?? new string[] { }).ToList();
-
- excludeItemTypes.Add(typeof(Year).Name);
- excludeItemTypes.Add(typeof(Folder).Name);
-
- if (query.IncludeGenres && (includeItemTypes.Count == 0 || includeItemTypes.Contains("Genre", StringComparer.OrdinalIgnoreCase)))
- {
- if (!query.IncludeMedia)
- {
- AddIfMissing(includeItemTypes, typeof(Genre).Name);
- AddIfMissing(includeItemTypes, typeof(GameGenre).Name);
- AddIfMissing(includeItemTypes, typeof(MusicGenre).Name);
- }
- }
- else
- {
- AddIfMissing(excludeItemTypes, typeof(Genre).Name);
- AddIfMissing(excludeItemTypes, typeof(GameGenre).Name);
- AddIfMissing(excludeItemTypes, typeof(MusicGenre).Name);
- }
-
- if (query.IncludePeople && (includeItemTypes.Count == 0 || includeItemTypes.Contains("People", StringComparer.OrdinalIgnoreCase) || includeItemTypes.Contains("Person", StringComparer.OrdinalIgnoreCase)))
- {
- if (!query.IncludeMedia)
- {
- AddIfMissing(includeItemTypes, typeof(Person).Name);
- }
- }
- else
- {
- AddIfMissing(excludeItemTypes, typeof(Person).Name);
- }
-
- if (query.IncludeStudios && (includeItemTypes.Count == 0 || includeItemTypes.Contains("Studio", StringComparer.OrdinalIgnoreCase)))
- {
- if (!query.IncludeMedia)
- {
- AddIfMissing(includeItemTypes, typeof(Studio).Name);
- }
- }
- else
- {
- AddIfMissing(excludeItemTypes, typeof(Studio).Name);
- }
-
- if (query.IncludeArtists && (includeItemTypes.Count == 0 || includeItemTypes.Contains("MusicArtist", StringComparer.OrdinalIgnoreCase)))
- {
- if (!query.IncludeMedia)
- {
- AddIfMissing(includeItemTypes, typeof(MusicArtist).Name);
- }
- }
- else
- {
- AddIfMissing(excludeItemTypes, typeof(MusicArtist).Name);
- }
-
- AddIfMissing(excludeItemTypes, typeof(CollectionFolder).Name);
-
- var mediaItems = _libraryManager.GetItemList(new InternalItemsQuery(user)
- {
- NameContains = searchTerm,
- ExcludeItemTypes = excludeItemTypes.ToArray(),
- IncludeItemTypes = includeItemTypes.ToArray(),
- Limit = query.Limit,
- IncludeItemsByName = true,
- IsVirtualItem = false
- });
-
- // Add search hints based on item name
- hints.AddRange(mediaItems.Select(item =>
- {
- var index = GetIndex(item.Name, searchTerm, terms);
-
- return new Tuple<BaseItem, string, int>(item, index.Item1, index.Item2);
- }));
-
- var returnValue = hints.Where(i => i.Item3 >= 0).OrderBy(i => i.Item3).Select(i => new SearchHintInfo
- {
- Item = i.Item1,
- MatchedTerm = i.Item2
- });
-
- return Task.FromResult(returnValue);
- }
-
- /// <summary>
- /// Gets the index.
- /// </summary>
- /// <param name="input">The input.</param>
- /// <param name="searchInput">The search input.</param>
- /// <param name="searchWords">The search input.</param>
- /// <returns>System.Int32.</returns>
- private Tuple<string, int> GetIndex(string input, string searchInput, List<string> searchWords)
- {
- if (string.IsNullOrWhiteSpace(input))
- {
- throw new ArgumentNullException("input");
- }
-
- input = input.RemoveDiacritics();
-
- if (string.Equals(input, searchInput, StringComparison.OrdinalIgnoreCase))
- {
- return new Tuple<string, int>(searchInput, 0);
- }
-
- var index = input.IndexOf(searchInput, StringComparison.OrdinalIgnoreCase);
-
- if (index == 0)
- {
- return new Tuple<string, int>(searchInput, 1);
- }
- if (index > 0)
- {
- return new Tuple<string, int>(searchInput, 2);
- }
-
- var items = GetWords(input);
-
- for (var i = 0; i < searchWords.Count; i++)
- {
- var searchTerm = searchWords[i];
-
- for (var j = 0; j < items.Count; j++)
- {
- var item = items[j];
-
- if (string.Equals(item, searchTerm, StringComparison.OrdinalIgnoreCase))
- {
- return new Tuple<string, int>(searchTerm, 3 + (i + 1) * (j + 1));
- }
-
- index = item.IndexOf(searchTerm, StringComparison.OrdinalIgnoreCase);
-
- if (index == 0)
- {
- return new Tuple<string, int>(searchTerm, 4 + (i + 1) * (j + 1));
- }
- if (index > 0)
- {
- return new Tuple<string, int>(searchTerm, 5 + (i + 1) * (j + 1));
- }
- }
- }
- return new Tuple<string, int>(null, -1);
- }
-
- /// <summary>
- /// Gets the words.
- /// </summary>
- /// <param name="term">The term.</param>
- /// <returns>System.String[][].</returns>
- private List<string> GetWords(string term)
- {
- var stoplist = GetStopList().ToList();
-
- return term.Split()
- .Where(i => !string.IsNullOrWhiteSpace(i) && !stoplist.Contains(i, StringComparer.OrdinalIgnoreCase))
- .ToList();
- }
-
- private IEnumerable<string> GetStopList()
- {
- return new[]
- {
- "the",
- "a",
- "of",
- "an"
- };
- }
- }
-}
diff --git a/MediaBrowser.Server.Implementations/Library/UserViewManager.cs b/MediaBrowser.Server.Implementations/Library/UserViewManager.cs
deleted file mode 100644
index 6a4e26ff9..000000000
--- a/MediaBrowser.Server.Implementations/Library/UserViewManager.cs
+++ /dev/null
@@ -1,292 +0,0 @@
-using MediaBrowser.Controller.Channels;
-using MediaBrowser.Controller.Configuration;
-using MediaBrowser.Controller.Entities;
-using MediaBrowser.Controller.Library;
-using MediaBrowser.Controller.LiveTv;
-using MediaBrowser.Model.Channels;
-using MediaBrowser.Model.Entities;
-using MediaBrowser.Model.Library;
-using MediaBrowser.Model.Querying;
-using System;
-using System.Collections.Generic;
-using System.Linq;
-using System.Threading;
-using System.Threading.Tasks;
-using MediaBrowser.Controller.Entities.Audio;
-using MediaBrowser.Model.Globalization;
-
-namespace MediaBrowser.Server.Implementations.Library
-{
- public class UserViewManager : IUserViewManager
- {
- private readonly ILibraryManager _libraryManager;
- private readonly ILocalizationManager _localizationManager;
- private readonly IUserManager _userManager;
-
- private readonly IChannelManager _channelManager;
- private readonly ILiveTvManager _liveTvManager;
- private readonly IServerConfigurationManager _config;
-
- public UserViewManager(ILibraryManager libraryManager, ILocalizationManager localizationManager, IUserManager userManager, IChannelManager channelManager, ILiveTvManager liveTvManager, IServerConfigurationManager config)
- {
- _libraryManager = libraryManager;
- _localizationManager = localizationManager;
- _userManager = userManager;
- _channelManager = channelManager;
- _liveTvManager = liveTvManager;
- _config = config;
- }
-
- public async Task<IEnumerable<Folder>> GetUserViews(UserViewQuery query, CancellationToken cancellationToken)
- {
- var user = _userManager.GetUserById(query.UserId);
-
- var folders = user.RootFolder
- .GetChildren(user, true)
- .OfType<Folder>()
- .ToList();
-
- if (!query.IncludeHidden)
- {
- folders = folders.Where(i =>
- {
- var hidden = i as IHiddenFromDisplay;
- return hidden == null || !hidden.IsHiddenFromUser(user);
- }).ToList();
- }
-
- var plainFolderIds = user.Configuration.PlainFolderViews.Select(i => new Guid(i)).ToList();
-
- var groupedFolders = new List<ICollectionFolder>();
-
- var list = new List<Folder>();
-
- foreach (var folder in folders)
- {
- var collectionFolder = folder as ICollectionFolder;
- var folderViewType = collectionFolder == null ? null : collectionFolder.CollectionType;
-
- if (UserView.IsUserSpecific(folder))
- {
- list.Add(await _libraryManager.GetNamedView(user, folder.Name, folder.Id.ToString("N"), folderViewType, null, cancellationToken).ConfigureAwait(false));
- continue;
- }
-
- if (plainFolderIds.Contains(folder.Id) && UserView.IsEligibleForEnhancedView(folderViewType))
- {
- list.Add(folder);
- continue;
- }
-
- if (collectionFolder != null && UserView.IsEligibleForGrouping(folder) && user.IsFolderGrouped(folder.Id))
- {
- groupedFolders.Add(collectionFolder);
- continue;
- }
-
- if (query.PresetViews.Contains(folderViewType ?? string.Empty, StringComparer.OrdinalIgnoreCase))
- {
- list.Add(await GetUserView(folder, folderViewType, string.Empty, cancellationToken).ConfigureAwait(false));
- }
- else
- {
- list.Add(folder);
- }
- }
-
- foreach (var viewType in new[] { CollectionType.Movies, CollectionType.TvShows })
- {
- var parents = groupedFolders.Where(i => string.Equals(i.CollectionType, viewType, StringComparison.OrdinalIgnoreCase) || string.IsNullOrWhiteSpace(i.CollectionType))
- .ToList();
-
- if (parents.Count > 0)
- {
- list.Add(await GetUserView(parents, viewType, string.Empty, user, query.PresetViews, cancellationToken).ConfigureAwait(false));
- }
- }
-
- if (_config.Configuration.EnableFolderView)
- {
- var name = _localizationManager.GetLocalizedString("ViewType" + CollectionType.Folders);
- list.Add(await _libraryManager.GetNamedView(name, CollectionType.Folders, string.Empty, cancellationToken).ConfigureAwait(false));
- }
-
- if (query.IncludeExternalContent)
- {
- var channelResult = await _channelManager.GetChannelsInternal(new ChannelQuery
- {
- UserId = query.UserId
-
- }, cancellationToken).ConfigureAwait(false);
-
- var channels = channelResult.Items;
-
- if (_config.Configuration.EnableChannelView && channels.Length > 0)
- {
- list.Add(await _channelManager.GetInternalChannelFolder(cancellationToken).ConfigureAwait(false));
- }
- else
- {
- list.AddRange(channels);
- }
-
- if (_liveTvManager.GetEnabledUsers().Select(i => i.Id.ToString("N")).Contains(query.UserId))
- {
- list.Add(await _liveTvManager.GetInternalLiveTvFolder(CancellationToken.None).ConfigureAwait(false));
- }
- }
-
- var sorted = _libraryManager.Sort(list, user, new[] { ItemSortBy.SortName }, SortOrder.Ascending).ToList();
-
- var orders = user.Configuration.OrderedViews.ToList();
-
- return list
- .OrderBy(i =>
- {
- var index = orders.IndexOf(i.Id.ToString("N"));
-
- if (index == -1)
- {
- var view = i as UserView;
- if (view != null)
- {
- if (view.DisplayParentId != Guid.Empty)
- {
- index = orders.IndexOf(view.DisplayParentId.ToString("N"));
- }
- }
- }
-
- return index == -1 ? int.MaxValue : index;
- })
- .ThenBy(sorted.IndexOf)
- .ThenBy(i => i.SortName);
- }
-
- public Task<UserView> GetUserSubView(string name, string parentId, string type, string sortName, CancellationToken cancellationToken)
- {
- var uniqueId = parentId + "subview" + type;
-
- return _libraryManager.GetNamedView(name, parentId, type, sortName, uniqueId, cancellationToken);
- }
-
- public Task<UserView> GetUserSubView(string parentId, string type, string sortName, CancellationToken cancellationToken)
- {
- var name = _localizationManager.GetLocalizedString("ViewType" + type);
-
- return GetUserSubView(name, parentId, type, sortName, cancellationToken);
- }
-
- private async Task<Folder> GetUserView(List<ICollectionFolder> parents, string viewType, string sortName, User user, string[] presetViews, CancellationToken cancellationToken)
- {
- if (parents.Count == 1 && parents.All(i => string.Equals(i.CollectionType, viewType, StringComparison.OrdinalIgnoreCase)))
- {
- if (!presetViews.Contains(viewType, StringComparer.OrdinalIgnoreCase))
- {
- return (Folder)parents[0];
- }
-
- return await GetUserView((Folder)parents[0], viewType, string.Empty, cancellationToken).ConfigureAwait(false);
- }
-
- var name = _localizationManager.GetLocalizedString("ViewType" + viewType);
- return await _libraryManager.GetNamedView(user, name, viewType, sortName, cancellationToken).ConfigureAwait(false);
- }
-
- public Task<UserView> GetUserView(Folder parent, string viewType, string sortName, CancellationToken cancellationToken)
- {
- return _libraryManager.GetShadowView(parent, viewType, sortName, cancellationToken);
- }
-
- public List<Tuple<BaseItem, List<BaseItem>>> GetLatestItems(LatestItemsQuery request)
- {
- var user = _userManager.GetUserById(request.UserId);
-
- var libraryItems = GetItemsForLatestItems(user, request);
-
- var list = new List<Tuple<BaseItem, List<BaseItem>>>();
-
- foreach (var item in libraryItems)
- {
- // Only grab the index container for media
- var container = item.IsFolder || !request.GroupItems ? null : item.LatestItemsIndexContainer;
-
- if (container == null)
- {
- list.Add(new Tuple<BaseItem, List<BaseItem>>(null, new List<BaseItem> { item }));
- }
- else
- {
- var current = list.FirstOrDefault(i => i.Item1 != null && i.Item1.Id == container.Id);
-
- if (current != null)
- {
- current.Item2.Add(item);
- }
- else
- {
- list.Add(new Tuple<BaseItem, List<BaseItem>>(container, new List<BaseItem> { item }));
- }
- }
-
- if (list.Count >= request.Limit)
- {
- break;
- }
- }
-
- return list;
- }
-
- private IEnumerable<BaseItem> GetItemsForLatestItems(User user, LatestItemsQuery request)
- {
- var parentId = request.ParentId;
-
- var includeItemTypes = request.IncludeItemTypes;
- var limit = request.Limit ?? 10;
-
- var parentIds = string.IsNullOrEmpty(parentId)
- ? new string[] { }
- : new[] { parentId };
-
- if (parentIds.Length == 0)
- {
- parentIds = user.RootFolder.GetChildren(user, true)
- .OfType<Folder>()
- .Select(i => i.Id.ToString("N"))
- .Where(i => !user.Configuration.LatestItemsExcludes.Contains(i))
- .ToArray();
- }
-
- if (parentIds.Length == 0)
- {
- return new List<BaseItem>();
- }
-
- var excludeItemTypes = includeItemTypes.Length == 0 ? new[]
- {
- typeof(Person).Name,
- typeof(Studio).Name,
- typeof(Year).Name,
- typeof(GameGenre).Name,
- typeof(MusicGenre).Name,
- typeof(Genre).Name
-
- } : new string[] { };
-
- return _libraryManager.GetItemList(new InternalItemsQuery(user)
- {
- IncludeItemTypes = includeItemTypes,
- SortOrder = SortOrder.Descending,
- SortBy = new[] { ItemSortBy.DateCreated },
- IsFolder = includeItemTypes.Length == 0 ? false : (bool?)null,
- ExcludeItemTypes = excludeItemTypes,
- ExcludeLocationTypes = new[] { LocationType.Virtual },
- Limit = limit * 5,
- SourceTypes = parentIds.Length == 0 ? new[] { SourceType.Library } : new SourceType[] { },
- IsPlayed = request.IsPlayed
-
- }, parentIds);
- }
- }
-}
diff --git a/MediaBrowser.Server.Implementations/Library/Validators/ArtistsPostScanTask.cs b/MediaBrowser.Server.Implementations/Library/Validators/ArtistsPostScanTask.cs
deleted file mode 100644
index 91b035a35..000000000
--- a/MediaBrowser.Server.Implementations/Library/Validators/ArtistsPostScanTask.cs
+++ /dev/null
@@ -1,44 +0,0 @@
-using MediaBrowser.Controller.Library;
-using MediaBrowser.Model.Logging;
-using System;
-using System.Threading;
-using System.Threading.Tasks;
-using MediaBrowser.Controller.Persistence;
-
-namespace MediaBrowser.Server.Implementations.Library.Validators
-{
- /// <summary>
- /// Class ArtistsPostScanTask
- /// </summary>
- public class ArtistsPostScanTask : ILibraryPostScanTask
- {
- /// <summary>
- /// The _library manager
- /// </summary>
- private readonly ILibraryManager _libraryManager;
- private readonly ILogger _logger;
- private readonly IItemRepository _itemRepo;
-
- /// <summary>
- /// Initializes a new instance of the <see cref="ArtistsPostScanTask" /> class.
- /// </summary>
- /// <param name="libraryManager">The library manager.</param>
- public ArtistsPostScanTask(ILibraryManager libraryManager, ILogger logger, IItemRepository itemRepo)
- {
- _libraryManager = libraryManager;
- _logger = logger;
- _itemRepo = itemRepo;
- }
-
- /// <summary>
- /// Runs the specified progress.
- /// </summary>
- /// <param name="progress">The progress.</param>
- /// <param name="cancellationToken">The cancellation token.</param>
- /// <returns>Task.</returns>
- public Task Run(IProgress<double> progress, CancellationToken cancellationToken)
- {
- return new ArtistsValidator(_libraryManager, _logger, _itemRepo).Run(progress, cancellationToken);
- }
- }
-}
diff --git a/MediaBrowser.Server.Implementations/Library/Validators/ArtistsValidator.cs b/MediaBrowser.Server.Implementations/Library/Validators/ArtistsValidator.cs
deleted file mode 100644
index 3dcdbeae9..000000000
--- a/MediaBrowser.Server.Implementations/Library/Validators/ArtistsValidator.cs
+++ /dev/null
@@ -1,84 +0,0 @@
-using MediaBrowser.Controller.Entities.Audio;
-using MediaBrowser.Controller.Library;
-using MediaBrowser.Model.Logging;
-using System;
-using System.IO;
-using System.Linq;
-using System.Threading;
-using System.Threading.Tasks;
-using MediaBrowser.Controller.Entities;
-using MediaBrowser.Controller.Persistence;
-
-namespace MediaBrowser.Server.Implementations.Library.Validators
-{
- /// <summary>
- /// Class ArtistsValidator
- /// </summary>
- public class ArtistsValidator
- {
- /// <summary>
- /// The _library manager
- /// </summary>
- private readonly ILibraryManager _libraryManager;
-
- /// <summary>
- /// The _logger
- /// </summary>
- private readonly ILogger _logger;
- private readonly IItemRepository _itemRepo;
-
- /// <summary>
- /// Initializes a new instance of the <see cref="ArtistsPostScanTask" /> class.
- /// </summary>
- /// <param name="libraryManager">The library manager.</param>
- /// <param name="logger">The logger.</param>
- public ArtistsValidator(ILibraryManager libraryManager, ILogger logger, IItemRepository itemRepo)
- {
- _libraryManager = libraryManager;
- _logger = logger;
- _itemRepo = itemRepo;
- }
-
- /// <summary>
- /// Runs the specified progress.
- /// </summary>
- /// <param name="progress">The progress.</param>
- /// <param name="cancellationToken">The cancellation token.</param>
- /// <returns>Task.</returns>
- public async Task Run(IProgress<double> progress, CancellationToken cancellationToken)
- {
- var names = _itemRepo.GetAllArtistNames();
-
- var numComplete = 0;
- var count = names.Count;
-
- foreach (var name in names)
- {
- try
- {
- var item = _libraryManager.GetArtist(name);
-
- await item.RefreshMetadata(cancellationToken).ConfigureAwait(false);
- }
- catch (OperationCanceledException)
- {
- // Don't clutter the log
- break;
- }
- catch (Exception ex)
- {
- _logger.ErrorException("Error refreshing {0}", ex, name);
- }
-
- numComplete++;
- double percent = numComplete;
- percent /= count;
- percent *= 100;
-
- progress.Report(percent);
- }
-
- progress.Report(100);
- }
- }
-}
diff --git a/MediaBrowser.Server.Implementations/Library/Validators/GameGenresPostScanTask.cs b/MediaBrowser.Server.Implementations/Library/Validators/GameGenresPostScanTask.cs
deleted file mode 100644
index f3891180e..000000000
--- a/MediaBrowser.Server.Implementations/Library/Validators/GameGenresPostScanTask.cs
+++ /dev/null
@@ -1,45 +0,0 @@
-using MediaBrowser.Controller.Library;
-using MediaBrowser.Model.Logging;
-using System;
-using System.Threading;
-using System.Threading.Tasks;
-using MediaBrowser.Controller.Persistence;
-
-namespace MediaBrowser.Server.Implementations.Library.Validators
-{
- /// <summary>
- /// Class GameGenresPostScanTask
- /// </summary>
- public class GameGenresPostScanTask : ILibraryPostScanTask
- {
- /// <summary>
- /// The _library manager
- /// </summary>
- private readonly ILibraryManager _libraryManager;
- private readonly ILogger _logger;
- private readonly IItemRepository _itemRepo;
-
- /// <summary>
- /// Initializes a new instance of the <see cref="GameGenresPostScanTask" /> class.
- /// </summary>
- /// <param name="libraryManager">The library manager.</param>
- /// <param name="logger">The logger.</param>
- public GameGenresPostScanTask(ILibraryManager libraryManager, ILogger logger, IItemRepository itemRepo)
- {
- _libraryManager = libraryManager;
- _logger = logger;
- _itemRepo = itemRepo;
- }
-
- /// <summary>
- /// Runs the specified progress.
- /// </summary>
- /// <param name="progress">The progress.</param>
- /// <param name="cancellationToken">The cancellation token.</param>
- /// <returns>Task.</returns>
- public Task Run(IProgress<double> progress, CancellationToken cancellationToken)
- {
- return new GameGenresValidator(_libraryManager, _logger, _itemRepo).Run(progress, cancellationToken);
- }
- }
-}
diff --git a/MediaBrowser.Server.Implementations/Library/Validators/GameGenresValidator.cs b/MediaBrowser.Server.Implementations/Library/Validators/GameGenresValidator.cs
deleted file mode 100644
index b06c0b3b9..000000000
--- a/MediaBrowser.Server.Implementations/Library/Validators/GameGenresValidator.cs
+++ /dev/null
@@ -1,74 +0,0 @@
-using MediaBrowser.Controller.Entities;
-using MediaBrowser.Controller.Library;
-using MediaBrowser.Model.Logging;
-using System;
-using System.Linq;
-using System.Threading;
-using System.Threading.Tasks;
-using MediaBrowser.Controller.Persistence;
-
-namespace MediaBrowser.Server.Implementations.Library.Validators
-{
- class GameGenresValidator
- {
- /// <summary>
- /// The _library manager
- /// </summary>
- private readonly ILibraryManager _libraryManager;
-
- /// <summary>
- /// The _logger
- /// </summary>
- private readonly ILogger _logger;
- private readonly IItemRepository _itemRepo;
-
- public GameGenresValidator(ILibraryManager libraryManager, ILogger logger, IItemRepository itemRepo)
- {
- _libraryManager = libraryManager;
- _logger = logger;
- _itemRepo = itemRepo;
- }
-
- /// <summary>
- /// Runs the specified progress.
- /// </summary>
- /// <param name="progress">The progress.</param>
- /// <param name="cancellationToken">The cancellation token.</param>
- /// <returns>Task.</returns>
- public async Task Run(IProgress<double> progress, CancellationToken cancellationToken)
- {
- var names = _itemRepo.GetGameGenreNames();
-
- var numComplete = 0;
- var count = names.Count;
-
- foreach (var name in names)
- {
- try
- {
- var item = _libraryManager.GetGameGenre(name);
-
- await item.RefreshMetadata(cancellationToken).ConfigureAwait(false);
- }
- catch (OperationCanceledException)
- {
- // Don't clutter the log
- break;
- }
- catch (Exception ex)
- {
- _logger.ErrorException("Error refreshing {0}", ex, name);
- }
-
- numComplete++;
- double percent = numComplete;
- percent /= count;
- percent *= 100;
-
- progress.Report(percent);
- }
-
- progress.Report(100);
- }
- }
-}
diff --git a/MediaBrowser.Server.Implementations/Library/Validators/GenresPostScanTask.cs b/MediaBrowser.Server.Implementations/Library/Validators/GenresPostScanTask.cs
deleted file mode 100644
index ed2429769..000000000
--- a/MediaBrowser.Server.Implementations/Library/Validators/GenresPostScanTask.cs
+++ /dev/null
@@ -1,42 +0,0 @@
-using MediaBrowser.Controller.Library;
-using System;
-using System.Threading;
-using System.Threading.Tasks;
-using MediaBrowser.Controller.Persistence;
-using MediaBrowser.Model.Logging;
-
-namespace MediaBrowser.Server.Implementations.Library.Validators
-{
- public class GenresPostScanTask : ILibraryPostScanTask
- {
- /// <summary>
- /// The _library manager
- /// </summary>
- private readonly ILibraryManager _libraryManager;
- private readonly ILogger _logger;
- private readonly IItemRepository _itemRepo;
-
- /// <summary>
- /// Initializes a new instance of the <see cref="ArtistsPostScanTask" /> class.
- /// </summary>
- /// <param name="libraryManager">The library manager.</param>
- /// <param name="logger">The logger.</param>
- public GenresPostScanTask(ILibraryManager libraryManager, ILogger logger, IItemRepository itemRepo)
- {
- _libraryManager = libraryManager;
- _logger = logger;
- _itemRepo = itemRepo;
- }
-
- /// <summary>
- /// Runs the specified progress.
- /// </summary>
- /// <param name="progress">The progress.</param>
- /// <param name="cancellationToken">The cancellation token.</param>
- /// <returns>Task.</returns>
- public Task Run(IProgress<double> progress, CancellationToken cancellationToken)
- {
- return new GenresValidator(_libraryManager, _logger, _itemRepo).Run(progress, cancellationToken);
- }
- }
-}
diff --git a/MediaBrowser.Server.Implementations/Library/Validators/GenresValidator.cs b/MediaBrowser.Server.Implementations/Library/Validators/GenresValidator.cs
deleted file mode 100644
index f35bb5136..000000000
--- a/MediaBrowser.Server.Implementations/Library/Validators/GenresValidator.cs
+++ /dev/null
@@ -1,75 +0,0 @@
-using MediaBrowser.Controller.Entities;
-using MediaBrowser.Controller.Entities.Audio;
-using MediaBrowser.Controller.Library;
-using MediaBrowser.Model.Logging;
-using System;
-using System.Linq;
-using System.Threading;
-using System.Threading.Tasks;
-using MediaBrowser.Controller.Persistence;
-
-namespace MediaBrowser.Server.Implementations.Library.Validators
-{
- class GenresValidator
- {
- /// <summary>
- /// The _library manager
- /// </summary>
- private readonly ILibraryManager _libraryManager;
- private readonly IItemRepository _itemRepo;
-
- /// <summary>
- /// The _logger
- /// </summary>
- private readonly ILogger _logger;
-
- public GenresValidator(ILibraryManager libraryManager, ILogger logger, IItemRepository itemRepo)
- {
- _libraryManager = libraryManager;
- _logger = logger;
- _itemRepo = itemRepo;
- }
-
- /// <summary>
- /// Runs the specified progress.
- /// </summary>
- /// <param name="progress">The progress.</param>
- /// <param name="cancellationToken">The cancellation token.</param>
- /// <returns>Task.</returns>
- public async Task Run(IProgress<double> progress, CancellationToken cancellationToken)
- {
- var names = _itemRepo.GetGenreNames();
-
- var numComplete = 0;
- var count = names.Count;
-
- foreach (var name in names)
- {
- try
- {
- var item = _libraryManager.GetGenre(name);
-
- await item.RefreshMetadata(cancellationToken).ConfigureAwait(false);
- }
- catch (OperationCanceledException)
- {
- // Don't clutter the log
- break;
- }
- catch (Exception ex)
- {
- _logger.ErrorException("Error refreshing {0}", ex, name);
- }
-
- numComplete++;
- double percent = numComplete;
- percent /= count;
- percent *= 100;
-
- progress.Report(percent);
- }
-
- progress.Report(100);
- }
- }
-}
diff --git a/MediaBrowser.Server.Implementations/Library/Validators/MusicGenresPostScanTask.cs b/MediaBrowser.Server.Implementations/Library/Validators/MusicGenresPostScanTask.cs
deleted file mode 100644
index 777532ff8..000000000
--- a/MediaBrowser.Server.Implementations/Library/Validators/MusicGenresPostScanTask.cs
+++ /dev/null
@@ -1,45 +0,0 @@
-using MediaBrowser.Controller.Library;
-using MediaBrowser.Model.Logging;
-using System;
-using System.Threading;
-using System.Threading.Tasks;
-using MediaBrowser.Controller.Persistence;
-
-namespace MediaBrowser.Server.Implementations.Library.Validators
-{
- /// <summary>
- /// Class MusicGenresPostScanTask
- /// </summary>
- public class MusicGenresPostScanTask : ILibraryPostScanTask
- {
- /// <summary>
- /// The _library manager
- /// </summary>
- private readonly ILibraryManager _libraryManager;
- private readonly ILogger _logger;
- private readonly IItemRepository _itemRepo;
-
- /// <summary>
- /// Initializes a new instance of the <see cref="ArtistsPostScanTask" /> class.
- /// </summary>
- /// <param name="libraryManager">The library manager.</param>
- /// <param name="logger">The logger.</param>
- public MusicGenresPostScanTask(ILibraryManager libraryManager, ILogger logger, IItemRepository itemRepo)
- {
- _libraryManager = libraryManager;
- _logger = logger;
- _itemRepo = itemRepo;
- }
-
- /// <summary>
- /// Runs the specified progress.
- /// </summary>
- /// <param name="progress">The progress.</param>
- /// <param name="cancellationToken">The cancellation token.</param>
- /// <returns>Task.</returns>
- public Task Run(IProgress<double> progress, CancellationToken cancellationToken)
- {
- return new MusicGenresValidator(_libraryManager, _logger, _itemRepo).Run(progress, cancellationToken);
- }
- }
-}
diff --git a/MediaBrowser.Server.Implementations/Library/Validators/MusicGenresValidator.cs b/MediaBrowser.Server.Implementations/Library/Validators/MusicGenresValidator.cs
deleted file mode 100644
index 2be99f106..000000000
--- a/MediaBrowser.Server.Implementations/Library/Validators/MusicGenresValidator.cs
+++ /dev/null
@@ -1,75 +0,0 @@
-using MediaBrowser.Controller.Entities.Audio;
-using MediaBrowser.Controller.Library;
-using MediaBrowser.Model.Logging;
-using System;
-using System.Linq;
-using System.Threading;
-using System.Threading.Tasks;
-using MediaBrowser.Controller.Entities;
-using MediaBrowser.Controller.Persistence;
-
-namespace MediaBrowser.Server.Implementations.Library.Validators
-{
- class MusicGenresValidator
- {
- /// <summary>
- /// The _library manager
- /// </summary>
- private readonly ILibraryManager _libraryManager;
-
- /// <summary>
- /// The _logger
- /// </summary>
- private readonly ILogger _logger;
- private readonly IItemRepository _itemRepo;
-
- public MusicGenresValidator(ILibraryManager libraryManager, ILogger logger, IItemRepository itemRepo)
- {
- _libraryManager = libraryManager;
- _logger = logger;
- _itemRepo = itemRepo;
- }
-
- /// <summary>
- /// Runs the specified progress.
- /// </summary>
- /// <param name="progress">The progress.</param>
- /// <param name="cancellationToken">The cancellation token.</param>
- /// <returns>Task.</returns>
- public async Task Run(IProgress<double> progress, CancellationToken cancellationToken)
- {
- var names = _itemRepo.GetMusicGenreNames();
-
- var numComplete = 0;
- var count = names.Count;
-
- foreach (var name in names)
- {
- try
- {
- var item = _libraryManager.GetMusicGenre(name);
-
- await item.RefreshMetadata(cancellationToken).ConfigureAwait(false);
- }
- catch (OperationCanceledException)
- {
- // Don't clutter the log
- break;
- }
- catch (Exception ex)
- {
- _logger.ErrorException("Error refreshing {0}", ex, name);
- }
-
- numComplete++;
- double percent = numComplete;
- percent /= count;
- percent *= 100;
-
- progress.Report(percent);
- }
-
- progress.Report(100);
- }
- }
-}
diff --git a/MediaBrowser.Server.Implementations/Library/Validators/PeopleValidator.cs b/MediaBrowser.Server.Implementations/Library/Validators/PeopleValidator.cs
deleted file mode 100644
index d9a7199be..000000000
--- a/MediaBrowser.Server.Implementations/Library/Validators/PeopleValidator.cs
+++ /dev/null
@@ -1,172 +0,0 @@
-using MediaBrowser.Common.Progress;
-using MediaBrowser.Controller.Configuration;
-using MediaBrowser.Controller.Entities;
-using MediaBrowser.Controller.Library;
-using MediaBrowser.Controller.Providers;
-using MediaBrowser.Model.Configuration;
-using MediaBrowser.Model.Entities;
-using MediaBrowser.Model.Logging;
-using System;
-using System.Collections.Generic;
-using System.Linq;
-using System.Threading;
-using System.Threading.Tasks;
-using MediaBrowser.Common.IO;
-using MediaBrowser.Controller.IO;
-using MediaBrowser.Model.IO;
-
-namespace MediaBrowser.Server.Implementations.Library.Validators
-{
- /// <summary>
- /// Class PeopleValidator
- /// </summary>
- public class PeopleValidator
- {
- /// <summary>
- /// The _library manager
- /// </summary>
- private readonly ILibraryManager _libraryManager;
- /// <summary>
- /// The _logger
- /// </summary>
- private readonly ILogger _logger;
-
- private readonly IServerConfigurationManager _config;
- private readonly IFileSystem _fileSystem;
-
- /// <summary>
- /// Initializes a new instance of the <see cref="PeopleValidator" /> class.
- /// </summary>
- /// <param name="libraryManager">The library manager.</param>
- /// <param name="logger">The logger.</param>
- public PeopleValidator(ILibraryManager libraryManager, ILogger logger, IServerConfigurationManager config, IFileSystem fileSystem)
- {
- _libraryManager = libraryManager;
- _logger = logger;
- _config = config;
- _fileSystem = fileSystem;
- }
-
- private bool DownloadMetadata(PersonInfo i, PeopleMetadataOptions options)
- {
- if (i.IsType(PersonType.Actor))
- {
- return options.DownloadActorMetadata;
- }
- if (i.IsType(PersonType.Director))
- {
- return options.DownloadDirectorMetadata;
- }
- if (i.IsType(PersonType.Composer))
- {
- return options.DownloadComposerMetadata;
- }
- if (i.IsType(PersonType.Writer))
- {
- return options.DownloadWriterMetadata;
- }
- if (i.IsType(PersonType.Producer))
- {
- return options.DownloadProducerMetadata;
- }
- if (i.IsType(PersonType.GuestStar))
- {
- return options.DownloadGuestStarMetadata;
- }
-
- return options.DownloadOtherPeopleMetadata;
- }
-
- /// <summary>
- /// Validates the people.
- /// </summary>
- /// <param name="cancellationToken">The cancellation token.</param>
- /// <param name="progress">The progress.</param>
- /// <returns>Task.</returns>
- public async Task ValidatePeople(CancellationToken cancellationToken, IProgress<double> progress)
- {
- var innerProgress = new ActionableProgress<double>();
-
- innerProgress.RegisterAction(pct => progress.Report(pct * .15));
-
- var peopleOptions = _config.Configuration.PeopleMetadataOptions;
-
- var people = _libraryManager.GetPeople(new InternalPeopleQuery());
-
- var dict = new Dictionary<string, bool>(StringComparer.OrdinalIgnoreCase);
-
- foreach (var person in people)
- {
- var isMetadataEnabled = DownloadMetadata(person, peopleOptions);
-
- bool currentValue;
- if (dict.TryGetValue(person.Name, out currentValue))
- {
- if (!currentValue && isMetadataEnabled)
- {
- dict[person.Name] = true;
- }
- }
- else
- {
- dict[person.Name] = isMetadataEnabled;
- }
- }
-
- var numComplete = 0;
-
- _logger.Debug("Will refresh {0} people", dict.Count);
-
- var numPeople = dict.Count;
-
- foreach (var person in dict)
- {
- cancellationToken.ThrowIfCancellationRequested();
-
- try
- {
- var item = _libraryManager.GetPerson(person.Key);
-
- var hasMetdata = !string.IsNullOrWhiteSpace(item.Overview);
- var performFullRefresh = !hasMetdata && (DateTime.UtcNow - item.DateLastRefreshed).TotalDays >= 30;
-
- var defaultMetadataRefreshMode = performFullRefresh
- ? MetadataRefreshMode.FullRefresh
- : MetadataRefreshMode.Default;
-
- var imageRefreshMode = performFullRefresh
- ? ImageRefreshMode.FullRefresh
- : ImageRefreshMode.Default;
-
- var options = new MetadataRefreshOptions(_fileSystem)
- {
- MetadataRefreshMode = person.Value ? defaultMetadataRefreshMode : MetadataRefreshMode.ValidationOnly,
- ImageRefreshMode = person.Value ? imageRefreshMode : ImageRefreshMode.ValidationOnly,
- ForceSave = performFullRefresh
- };
-
- await item.RefreshMetadata(options, cancellationToken).ConfigureAwait(false);
- }
- catch (OperationCanceledException)
- {
- throw;
- }
- catch (Exception ex)
- {
- _logger.ErrorException("Error validating IBN entry {0}", ex, person);
- }
-
- // Update progress
- numComplete++;
- double percent = numComplete;
- percent /= numPeople;
-
- progress.Report(100 * percent);
- }
-
- progress.Report(100);
-
- _logger.Info("People validation complete");
- }
- }
-}
diff --git a/MediaBrowser.Server.Implementations/Library/Validators/StudiosPostScanTask.cs b/MediaBrowser.Server.Implementations/Library/Validators/StudiosPostScanTask.cs
deleted file mode 100644
index 77c6d5146..000000000
--- a/MediaBrowser.Server.Implementations/Library/Validators/StudiosPostScanTask.cs
+++ /dev/null
@@ -1,45 +0,0 @@
-using MediaBrowser.Controller.Library;
-using MediaBrowser.Model.Logging;
-using System;
-using System.Threading;
-using System.Threading.Tasks;
-using MediaBrowser.Controller.Persistence;
-
-namespace MediaBrowser.Server.Implementations.Library.Validators
-{
- /// <summary>
- /// Class MusicGenresPostScanTask
- /// </summary>
- public class StudiosPostScanTask : ILibraryPostScanTask
- {
- /// <summary>
- /// The _library manager
- /// </summary>
- private readonly ILibraryManager _libraryManager;
-
- private readonly ILogger _logger;
- private readonly IItemRepository _itemRepo;
-
- /// <summary>
- /// Initializes a new instance of the <see cref="ArtistsPostScanTask" /> class.
- /// </summary>
- /// <param name="libraryManager">The library manager.</param>
- public StudiosPostScanTask(ILibraryManager libraryManager, ILogger logger, IItemRepository itemRepo)
- {
- _libraryManager = libraryManager;
- _logger = logger;
- _itemRepo = itemRepo;
- }
-
- /// <summary>
- /// Runs the specified progress.
- /// </summary>
- /// <param name="progress">The progress.</param>
- /// <param name="cancellationToken">The cancellation token.</param>
- /// <returns>Task.</returns>
- public Task Run(IProgress<double> progress, CancellationToken cancellationToken)
- {
- return new StudiosValidator(_libraryManager, _logger, _itemRepo).Run(progress, cancellationToken);
- }
- }
-}
diff --git a/MediaBrowser.Server.Implementations/Library/Validators/StudiosValidator.cs b/MediaBrowser.Server.Implementations/Library/Validators/StudiosValidator.cs
deleted file mode 100644
index a19b8158a..000000000
--- a/MediaBrowser.Server.Implementations/Library/Validators/StudiosValidator.cs
+++ /dev/null
@@ -1,74 +0,0 @@
-using MediaBrowser.Controller.Library;
-using MediaBrowser.Model.Logging;
-using System;
-using System.Linq;
-using System.Threading;
-using System.Threading.Tasks;
-using MediaBrowser.Controller.Entities;
-using MediaBrowser.Controller.Persistence;
-
-namespace MediaBrowser.Server.Implementations.Library.Validators
-{
- class StudiosValidator
- {
- /// <summary>
- /// The _library manager
- /// </summary>
- private readonly ILibraryManager _libraryManager;
-
- private readonly IItemRepository _itemRepo;
- /// <summary>
- /// The _logger
- /// </summary>
- private readonly ILogger _logger;
-
- public StudiosValidator(ILibraryManager libraryManager, ILogger logger, IItemRepository itemRepo)
- {
- _libraryManager = libraryManager;
- _logger = logger;
- _itemRepo = itemRepo;
- }
-
- /// <summary>
- /// Runs the specified progress.
- /// </summary>
- /// <param name="progress">The progress.</param>
- /// <param name="cancellationToken">The cancellation token.</param>
- /// <returns>Task.</returns>
- public async Task Run(IProgress<double> progress, CancellationToken cancellationToken)
- {
- var names = _itemRepo.GetStudioNames();
-
- var numComplete = 0;
- var count = names.Count;
-
- foreach (var name in names)
- {
- try
- {
- var item = _libraryManager.GetStudio(name);
-
- await item.RefreshMetadata(cancellationToken).ConfigureAwait(false);
- }
- catch (OperationCanceledException)
- {
- // Don't clutter the log
- break;
- }
- catch (Exception ex)
- {
- _logger.ErrorException("Error refreshing {0}", ex, name);
- }
-
- numComplete++;
- double percent = numComplete;
- percent /= count;
- percent *= 100;
-
- progress.Report(percent);
- }
-
- progress.Report(100);
- }
- }
-}
diff --git a/MediaBrowser.Server.Implementations/Library/Validators/YearsPostScanTask.cs b/MediaBrowser.Server.Implementations/Library/Validators/YearsPostScanTask.cs
deleted file mode 100644
index 164b14223..000000000
--- a/MediaBrowser.Server.Implementations/Library/Validators/YearsPostScanTask.cs
+++ /dev/null
@@ -1,55 +0,0 @@
-using MediaBrowser.Controller.Library;
-using MediaBrowser.Model.Logging;
-using System;
-using System.Threading;
-using System.Threading.Tasks;
-
-namespace MediaBrowser.Server.Implementations.Library.Validators
-{
- public class YearsPostScanTask : ILibraryPostScanTask
- {
- private readonly ILibraryManager _libraryManager;
- private readonly ILogger _logger;
-
- public YearsPostScanTask(ILibraryManager libraryManager, ILogger logger)
- {
- _libraryManager = libraryManager;
- _logger = logger;
- }
-
- public async Task Run(IProgress<double> progress, CancellationToken cancellationToken)
- {
- var yearNumber = 1900;
- var maxYear = DateTime.UtcNow.Year + 3;
- var count = maxYear - yearNumber + 1;
- var numComplete = 0;
-
- while (yearNumber < maxYear)
- {
- try
- {
- var year = _libraryManager.GetYear(yearNumber);
-
- await year.RefreshMetadata(cancellationToken).ConfigureAwait(false);
- }
- catch (OperationCanceledException)
- {
- // Don't clutter the log
- break;
- }
- catch (Exception ex)
- {
- _logger.ErrorException("Error refreshing year {0}", ex, yearNumber);
- }
-
- numComplete++;
- double percent = numComplete;
- percent /= count;
- percent *= 100;
-
- progress.Report(percent);
- yearNumber++;
- }
- }
- }
-}