aboutsummaryrefslogtreecommitdiff
path: root/MediaBrowser.Controller/Library
diff options
context:
space:
mode:
Diffstat (limited to 'MediaBrowser.Controller/Library')
-rw-r--r--MediaBrowser.Controller/Library/DeleteOptions.cs14
-rw-r--r--MediaBrowser.Controller/Library/IIntroProvider.cs32
-rw-r--r--MediaBrowser.Controller/Library/ILibraryManager.cs550
-rw-r--r--MediaBrowser.Controller/Library/ILibraryMonitor.cs43
-rw-r--r--MediaBrowser.Controller/Library/ILibraryPostScanTask.cs20
-rw-r--r--MediaBrowser.Controller/Library/ILiveStream.cs21
-rw-r--r--MediaBrowser.Controller/Library/IMediaSourceManager.cs100
-rw-r--r--MediaBrowser.Controller/Library/IMediaSourceProvider.cs25
-rw-r--r--MediaBrowser.Controller/Library/IMetadataFileSaver.cs19
-rw-r--r--MediaBrowser.Controller/Library/IMetadataSaver.cs33
-rw-r--r--MediaBrowser.Controller/Library/IMusicManager.cs25
-rw-r--r--MediaBrowser.Controller/Library/ISearchEngine.cs18
-rw-r--r--MediaBrowser.Controller/Library/IUserDataManager.cs67
-rw-r--r--MediaBrowser.Controller/Library/IUserManager.cs207
-rw-r--r--MediaBrowser.Controller/Library/IUserViewManager.cs19
-rw-r--r--MediaBrowser.Controller/Library/IntroInfo.cs19
-rw-r--r--MediaBrowser.Controller/Library/ItemChangeEventArgs.cs24
-rw-r--r--MediaBrowser.Controller/Library/ItemResolveArgs.cs281
-rw-r--r--MediaBrowser.Controller/Library/ItemUpdateType.cs14
-rw-r--r--MediaBrowser.Controller/Library/LibraryManagerExtensions.cs13
-rw-r--r--MediaBrowser.Controller/Library/MetadataConfigurationStore.cs29
-rw-r--r--MediaBrowser.Controller/Library/NameExtensions.cs26
-rw-r--r--MediaBrowser.Controller/Library/PlaybackProgressEventArgs.cs34
-rw-r--r--MediaBrowser.Controller/Library/PlaybackStopEventArgs.cs11
-rw-r--r--MediaBrowser.Controller/Library/Profiler.cs76
-rw-r--r--MediaBrowser.Controller/Library/SearchHintInfo.cs22
-rw-r--r--MediaBrowser.Controller/Library/TVUtils.cs59
-rw-r--r--MediaBrowser.Controller/Library/UserDataSaveEventArgs.cs39
28 files changed, 1840 insertions, 0 deletions
diff --git a/MediaBrowser.Controller/Library/DeleteOptions.cs b/MediaBrowser.Controller/Library/DeleteOptions.cs
new file mode 100644
index 000000000..822fc3dc3
--- /dev/null
+++ b/MediaBrowser.Controller/Library/DeleteOptions.cs
@@ -0,0 +1,14 @@
+
+namespace MediaBrowser.Controller.Library
+{
+ public class DeleteOptions
+ {
+ public bool DeleteFileLocation { get; set; }
+ public bool DeleteFromExternalProvider { get; set; }
+
+ public DeleteOptions()
+ {
+ DeleteFromExternalProvider = true;
+ }
+ }
+}
diff --git a/MediaBrowser.Controller/Library/IIntroProvider.cs b/MediaBrowser.Controller/Library/IIntroProvider.cs
new file mode 100644
index 000000000..611aab387
--- /dev/null
+++ b/MediaBrowser.Controller/Library/IIntroProvider.cs
@@ -0,0 +1,32 @@
+using MediaBrowser.Controller.Entities;
+using System.Collections.Generic;
+using System.Threading.Tasks;
+
+namespace MediaBrowser.Controller.Library
+{
+ /// <summary>
+ /// Class BaseIntroProvider
+ /// </summary>
+ public interface IIntroProvider
+ {
+ /// <summary>
+ /// Gets the intros.
+ /// </summary>
+ /// <param name="item">The item.</param>
+ /// <param name="user">The user.</param>
+ /// <returns>IEnumerable{System.String}.</returns>
+ Task<IEnumerable<IntroInfo>> GetIntros(BaseItem item, User user);
+
+ /// <summary>
+ /// Gets all intro files.
+ /// </summary>
+ /// <returns>IEnumerable{System.String}.</returns>
+ IEnumerable<string> GetAllIntroFiles();
+
+ /// <summary>
+ /// Gets the name.
+ /// </summary>
+ /// <value>The name.</value>
+ string Name { get; }
+ }
+}
diff --git a/MediaBrowser.Controller/Library/ILibraryManager.cs b/MediaBrowser.Controller/Library/ILibraryManager.cs
new file mode 100644
index 000000000..d572716fa
--- /dev/null
+++ b/MediaBrowser.Controller/Library/ILibraryManager.cs
@@ -0,0 +1,550 @@
+using MediaBrowser.Controller.Entities;
+using MediaBrowser.Controller.Entities.Audio;
+using MediaBrowser.Controller.Entities.TV;
+using MediaBrowser.Controller.Providers;
+using MediaBrowser.Controller.Resolvers;
+using MediaBrowser.Controller.Sorting;
+using MediaBrowser.Model.Entities;
+using MediaBrowser.Model.Querying;
+using System;
+using System.Collections.Generic;
+using System.Threading;
+using System.Threading.Tasks;
+
+using MediaBrowser.Controller.Configuration;
+using MediaBrowser.Controller.Dto;
+using MediaBrowser.Controller.IO;
+using MediaBrowser.Model.Configuration;
+using MediaBrowser.Model.Dto;
+using MediaBrowser.Model.IO;
+
+namespace MediaBrowser.Controller.Library
+{
+ /// <summary>
+ /// Interface ILibraryManager
+ /// </summary>
+ public interface ILibraryManager
+ {
+ /// <summary>
+ /// Resolves the path.
+ /// </summary>
+ /// <param name="fileInfo">The file information.</param>
+ /// <param name="parent">The parent.</param>
+ /// <returns>BaseItem.</returns>
+ BaseItem ResolvePath(FileSystemMetadata fileInfo,
+ Folder parent = null);
+
+ /// <summary>
+ /// Resolves a set of files into a list of BaseItem
+ /// </summary>
+ IEnumerable<BaseItem> ResolvePaths(IEnumerable<FileSystemMetadata> files,
+ IDirectoryService directoryService,
+ Folder parent,
+ LibraryOptions libraryOptions,
+ string collectionType = null);
+
+ /// <summary>
+ /// Gets the root folder.
+ /// </summary>
+ /// <value>The root folder.</value>
+ AggregateFolder RootFolder { get; }
+
+ /// <summary>
+ /// Gets a Person
+ /// </summary>
+ /// <param name="name">The name.</param>
+ /// <returns>Task{Person}.</returns>
+ Person GetPerson(string name);
+
+ /// <summary>
+ /// Finds the by path.
+ /// </summary>
+ /// <param name="path">The path.</param>
+ /// <returns>BaseItem.</returns>
+ BaseItem FindByPath(string path, bool? isFolder);
+
+ /// <summary>
+ /// Gets the artist.
+ /// </summary>
+ /// <param name="name">The name.</param>
+ /// <returns>Task{Artist}.</returns>
+ MusicArtist GetArtist(string name);
+ MusicArtist GetArtist(string name, DtoOptions options);
+ /// <summary>
+ /// Gets a Studio
+ /// </summary>
+ /// <param name="name">The name.</param>
+ /// <returns>Task{Studio}.</returns>
+ Studio GetStudio(string name);
+
+ /// <summary>
+ /// Gets a Genre
+ /// </summary>
+ /// <param name="name">The name.</param>
+ /// <returns>Task{Genre}.</returns>
+ Genre GetGenre(string name);
+
+ /// <summary>
+ /// Gets the genre.
+ /// </summary>
+ /// <param name="name">The name.</param>
+ /// <returns>Task{MusicGenre}.</returns>
+ MusicGenre GetMusicGenre(string name);
+
+ /// <summary>
+ /// Gets the game genre.
+ /// </summary>
+ /// <param name="name">The name.</param>
+ /// <returns>Task{GameGenre}.</returns>
+ GameGenre GetGameGenre(string name);
+
+ /// <summary>
+ /// Gets a Year
+ /// </summary>
+ /// <param name="value">The value.</param>
+ /// <returns>Task{Year}.</returns>
+ /// <exception cref="System.ArgumentOutOfRangeException"></exception>
+ Year GetYear(int value);
+
+ /// <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>
+ Task ValidatePeople(CancellationToken cancellationToken, IProgress<double> progress);
+
+ /// <summary>
+ /// Reloads the root media folder
+ /// </summary>
+ /// <param name="progress">The progress.</param>
+ /// <param name="cancellationToken">The cancellation token.</param>
+ /// <returns>Task.</returns>
+ Task ValidateMediaLibrary(IProgress<double> progress, CancellationToken cancellationToken);
+
+ /// <summary>
+ /// Queues the library scan.
+ /// </summary>
+ void QueueLibraryScan();
+
+ void UpdateImages(BaseItem item);
+
+ /// <summary>
+ /// Gets the default view.
+ /// </summary>
+ /// <returns>IEnumerable{VirtualFolderInfo}.</returns>
+ List<VirtualFolderInfo> GetVirtualFolders();
+
+ List<VirtualFolderInfo> GetVirtualFolders(bool includeRefreshState);
+
+ /// <summary>
+ /// Gets the item by id.
+ /// </summary>
+ /// <param name="id">The id.</param>
+ /// <returns>BaseItem.</returns>
+ BaseItem GetItemById(Guid id);
+
+ /// <summary>
+ /// Gets the intros.
+ /// </summary>
+ /// <param name="item">The item.</param>
+ /// <param name="user">The user.</param>
+ /// <returns>IEnumerable{System.String}.</returns>
+ Task<IEnumerable<Video>> GetIntros(BaseItem item, User user);
+
+ /// <summary>
+ /// Gets all intro files.
+ /// </summary>
+ /// <returns>IEnumerable{System.String}.</returns>
+ IEnumerable<string> GetAllIntroFiles();
+
+ /// <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>
+ void AddParts(IEnumerable<IResolverIgnoreRule> rules,
+ IEnumerable<IItemResolver> resolvers,
+ IEnumerable<IIntroProvider> introProviders,
+ IEnumerable<IBaseItemComparer> itemComparers,
+ IEnumerable<ILibraryPostScanTask> postscanTasks);
+
+ /// <summary>
+ /// Sorts the specified items.
+ /// </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>
+ IEnumerable<BaseItem> Sort(IEnumerable<BaseItem> items, User user, IEnumerable<string> sortBy, SortOrder sortOrder);
+ IEnumerable<BaseItem> Sort(IEnumerable<BaseItem> items, User user, IEnumerable<ValueTuple<string, SortOrder>> orderBy);
+
+ /// <summary>
+ /// Gets the user root folder.
+ /// </summary>
+ /// <returns>UserRootFolder.</returns>
+ Folder GetUserRootFolder();
+
+ /// <summary>
+ /// Creates the item.
+ /// </summary>
+ void CreateItem(BaseItem item, BaseItem parent);
+
+ /// <summary>
+ /// Creates the items.
+ /// </summary>
+ void CreateItems(IEnumerable<BaseItem> items, BaseItem parent, CancellationToken cancellationToken);
+
+ /// <summary>
+ /// Updates the item.
+ /// </summary>
+ void UpdateItems(List<BaseItem> items, BaseItem parent, ItemUpdateType updateReason, CancellationToken cancellationToken);
+ void UpdateItem(BaseItem item, BaseItem parent, ItemUpdateType updateReason, CancellationToken cancellationToken);
+
+ /// <summary>
+ /// Retrieves the item.
+ /// </summary>
+ /// <param name="id">The id.</param>
+ /// <returns>BaseItem.</returns>
+ BaseItem RetrieveItem(Guid id);
+
+ bool IsScanRunning { get; }
+
+ /// <summary>
+ /// Occurs when [item added].
+ /// </summary>
+ event EventHandler<ItemChangeEventArgs> ItemAdded;
+
+ /// <summary>
+ /// Occurs when [item updated].
+ /// </summary>
+ event EventHandler<ItemChangeEventArgs> ItemUpdated;
+ /// <summary>
+ /// Occurs when [item removed].
+ /// </summary>
+ event EventHandler<ItemChangeEventArgs> ItemRemoved;
+
+ /// <summary>
+ /// Finds the type of the collection.
+ /// </summary>
+ /// <param name="item">The item.</param>
+ /// <returns>System.String.</returns>
+ string GetContentType(BaseItem item);
+
+ /// <summary>
+ /// Gets the type of the inherited content.
+ /// </summary>
+ /// <param name="item">The item.</param>
+ /// <returns>System.String.</returns>
+ string GetInheritedContentType(BaseItem item);
+
+ /// <summary>
+ /// Gets the type of the configured content.
+ /// </summary>
+ /// <param name="item">The item.</param>
+ /// <returns>System.String.</returns>
+ string GetConfiguredContentType(BaseItem item);
+
+ /// <summary>
+ /// Gets the type of the configured content.
+ /// </summary>
+ /// <param name="path">The path.</param>
+ /// <returns>System.String.</returns>
+ string GetConfiguredContentType(string path);
+
+ /// <summary>
+ /// Normalizes the root path list.
+ /// </summary>
+ /// <param name="paths">The paths.</param>
+ /// <returns>IEnumerable{System.String}.</returns>
+ List<FileSystemMetadata> NormalizeRootPathList(IEnumerable<FileSystemMetadata> paths);
+
+ /// <summary>
+ /// Registers the item.
+ /// </summary>
+ /// <param name="item">The item.</param>
+ void RegisterItem(BaseItem item);
+
+ /// <summary>
+ /// Deletes the item.
+ /// </summary>
+ void DeleteItem(BaseItem item, DeleteOptions options);
+
+ /// <summary>
+ /// Deletes the item.
+ /// </summary>
+ void DeleteItem(BaseItem item, DeleteOptions options, bool notifyParentItem);
+
+ /// <summary>
+ /// Deletes the item.
+ /// </summary>
+ void DeleteItem(BaseItem item, DeleteOptions options, BaseItem parent, bool notifyParentItem);
+
+ /// <summary>
+ /// Gets the named view.
+ /// </summary>
+ /// <param name="user">The user.</param>
+ /// <param name="name">The name.</param>
+ /// <param name="parentId">The parent identifier.</param>
+ /// <param name="viewType">Type of the view.</param>
+ /// <param name="sortName">Name of the sort.</param>
+ UserView GetNamedView(User user,
+ string name,
+ Guid parentId,
+ string viewType,
+ string sortNamen);
+
+ /// <summary>
+ /// Gets the named view.
+ /// </summary>
+ /// <param name="user">The user.</param>
+ /// <param name="name">The name.</param>
+ /// <param name="viewType">Type of the view.</param>
+ /// <param name="sortName">Name of the sort.</param>
+ UserView GetNamedView(User user,
+ string name,
+ string viewType,
+ string sortName);
+
+ /// <summary>
+ /// Gets the named view.
+ /// </summary>
+ /// <param name="name">The name.</param>
+ /// <param name="viewType">Type of the view.</param>
+ /// <param name="sortName">Name of the sort.</param>
+ UserView GetNamedView(string name,
+ string viewType,
+ string sortName);
+
+ /// <summary>
+ /// Gets the named view.
+ /// </summary>
+ /// <param name="name">The name.</param>
+ /// <param name="parentId">The parent identifier.</param>
+ /// <param name="viewType">Type of the view.</param>
+ /// <param name="sortName">Name of the sort.</param>
+ /// <param name="uniqueId">The unique identifier.</param>
+ UserView GetNamedView(string name,
+ Guid parentId,
+ string viewType,
+ string sortName,
+ string uniqueId);
+
+ /// <summary>
+ /// Gets the shadow view.
+ /// </summary>
+ /// <param name="parent">The parent.</param>
+ /// <param name="viewType">Type of the view.</param>
+ /// <param name="sortName">Name of the sort.</param>
+ UserView GetShadowView(BaseItem parent,
+ string viewType,
+ string sortName);
+
+ /// <summary>
+ /// Determines whether [is video file] [the specified path].
+ /// </summary>
+ /// <param name="path">The path.</param>
+ /// <returns><c>true</c> if [is video file] [the specified path]; otherwise, <c>false</c>.</returns>
+ bool IsVideoFile(string path);
+
+ /// <summary>
+ /// Determines whether [is audio file] [the specified path].
+ /// </summary>
+ /// <param name="path">The path.</param>
+ /// <returns><c>true</c> if [is audio file] [the specified path]; otherwise, <c>false</c>.</returns>
+ bool IsAudioFile(string path);
+
+ bool IsAudioFile(string path, LibraryOptions libraryOptions);
+ bool IsVideoFile(string path, LibraryOptions libraryOptions);
+
+ /// <summary>
+ /// Gets the season number from path.
+ /// </summary>
+ /// <param name="path">The path.</param>
+ /// <returns>System.Nullable&lt;System.Int32&gt;.</returns>
+ int? GetSeasonNumberFromPath(string path);
+
+ /// <summary>
+ /// Fills the missing episode numbers from path.
+ /// </summary>
+ bool FillMissingEpisodeNumbersFromPath(Episode episode, bool forceRefresh);
+
+ /// <summary>
+ /// Parses the name.
+ /// </summary>
+ /// <param name="name">The name.</param>
+ /// <returns>ItemInfo.</returns>
+ ItemLookupInfo ParseName(string name);
+
+ /// <summary>
+ /// Gets the new item identifier.
+ /// </summary>
+ /// <param name="key">The key.</param>
+ /// <param name="type">The type.</param>
+ /// <returns>Guid.</returns>
+ Guid GetNewItemId(string key, Type type);
+
+ /// <summary>
+ /// Finds the trailers.
+ /// </summary>
+ /// <param name="owner">The owner.</param>
+ /// <param name="fileSystemChildren">The file system children.</param>
+ /// <param name="directoryService">The directory service.</param>
+ /// <returns>IEnumerable&lt;Trailer&gt;.</returns>
+ IEnumerable<Video> FindTrailers(BaseItem owner, List<FileSystemMetadata> fileSystemChildren,
+ IDirectoryService directoryService);
+
+ /// <summary>
+ /// Finds the extras.
+ /// </summary>
+ /// <param name="owner">The owner.</param>
+ /// <param name="fileSystemChildren">The file system children.</param>
+ /// <param name="directoryService">The directory service.</param>
+ /// <returns>IEnumerable&lt;Video&gt;.</returns>
+ IEnumerable<Video> FindExtras(BaseItem owner, List<FileSystemMetadata> fileSystemChildren,
+ IDirectoryService directoryService);
+
+ /// <summary>
+ /// Gets the collection folders.
+ /// </summary>
+ /// <param name="item">The item.</param>
+ /// <returns>IEnumerable&lt;Folder&gt;.</returns>
+ List<Folder> GetCollectionFolders(BaseItem item);
+
+ List<Folder> GetCollectionFolders(BaseItem item, List<Folder> allUserRootChildren);
+
+ LibraryOptions GetLibraryOptions(BaseItem item);
+
+ /// <summary>
+ /// Gets the people.
+ /// </summary>
+ /// <param name="item">The item.</param>
+ /// <returns>List&lt;PersonInfo&gt;.</returns>
+ List<PersonInfo> GetPeople(BaseItem item);
+
+ /// <summary>
+ /// Gets the people.
+ /// </summary>
+ /// <param name="query">The query.</param>
+ /// <returns>List&lt;PersonInfo&gt;.</returns>
+ List<PersonInfo> GetPeople(InternalPeopleQuery query);
+
+ /// <summary>
+ /// Gets the people items.
+ /// </summary>
+ /// <param name="query">The query.</param>
+ /// <returns>List&lt;Person&gt;.</returns>
+ List<Person> GetPeopleItems(InternalPeopleQuery query);
+
+ /// <summary>
+ /// Updates the people.
+ /// </summary>
+ /// <param name="item">The item.</param>
+ /// <param name="people">The people.</param>
+ void UpdatePeople(BaseItem item, List<PersonInfo> people);
+
+ /// <summary>
+ /// Gets the item ids.
+ /// </summary>
+ /// <param name="query">The query.</param>
+ /// <returns>List&lt;Guid&gt;.</returns>
+ List<Guid> GetItemIds(InternalItemsQuery query);
+
+ /// <summary>
+ /// Gets the people names.
+ /// </summary>
+ /// <param name="query">The query.</param>
+ /// <returns>List&lt;System.String&gt;.</returns>
+ List<string> GetPeopleNames(InternalPeopleQuery query);
+
+ /// <summary>
+ /// Queries the items.
+ /// </summary>
+ /// <param name="query">The query.</param>
+ /// <returns>QueryResult&lt;BaseItem&gt;.</returns>
+ QueryResult<BaseItem> QueryItems(InternalItemsQuery query);
+
+ string GetPathAfterNetworkSubstitution(string path, BaseItem ownerItem = null);
+
+ /// <summary>
+ /// Substitutes the path.
+ /// </summary>
+ /// <param name="path">The path.</param>
+ /// <param name="from">From.</param>
+ /// <param name="to">To.</param>
+ /// <returns>System.String.</returns>
+ string SubstitutePath(string path, string from, string to);
+
+ /// <summary>
+ /// Converts the image to local.
+ /// </summary>
+ /// <param name="item">The item.</param>
+ /// <param name="image">The image.</param>
+ /// <param name="imageIndex">Index of the image.</param>
+ /// <returns>Task.</returns>
+ Task<ItemImageInfo> ConvertImageToLocal(BaseItem item, ItemImageInfo image, int imageIndex);
+
+ /// <summary>
+ /// Gets the items.
+ /// </summary>
+ /// <param name="query">The query.</param>
+ /// <returns>QueryResult&lt;BaseItem&gt;.</returns>
+ List<BaseItem> GetItemList(InternalItemsQuery query);
+
+ List<BaseItem> GetItemList(InternalItemsQuery query, bool allowExternalContent);
+
+ /// <summary>
+ /// Gets the items.
+ /// </summary>
+ List<BaseItem> GetItemList(InternalItemsQuery query, List<BaseItem> parents);
+
+ /// <summary>
+ /// Gets the items result.
+ /// </summary>
+ /// <param name="query">The query.</param>
+ /// <returns>QueryResult&lt;BaseItem&gt;.</returns>
+ QueryResult<BaseItem> GetItemsResult(InternalItemsQuery query);
+
+ /// <summary>
+ /// Ignores the file.
+ /// </summary>
+ /// <param name="file">The file.</param>
+ /// <param name="parent">The parent.</param>
+ /// <returns><c>true</c> if XXXX, <c>false</c> otherwise.</returns>
+ bool IgnoreFile(FileSystemMetadata file, BaseItem parent);
+
+ Guid GetStudioId(string name);
+
+ Guid GetGenreId(string name);
+
+ Guid GetMusicGenreId(string name);
+
+ Guid GetGameGenreId(string name);
+
+ Task AddVirtualFolder(string name, string collectionType, LibraryOptions options, bool refreshLibrary);
+ Task RemoveVirtualFolder(string name, bool refreshLibrary);
+ void AddMediaPath(string virtualFolderName, MediaPathInfo path);
+ void UpdateMediaPath(string virtualFolderName, MediaPathInfo path);
+ void RemoveMediaPath(string virtualFolderName, string path);
+
+ QueryResult<Tuple<BaseItem, ItemCounts>> GetGenres(InternalItemsQuery query);
+ QueryResult<Tuple<BaseItem, ItemCounts>> GetMusicGenres(InternalItemsQuery query);
+ QueryResult<Tuple<BaseItem, ItemCounts>> GetGameGenres(InternalItemsQuery query);
+ QueryResult<Tuple<BaseItem, ItemCounts>> GetStudios(InternalItemsQuery query);
+ QueryResult<Tuple<BaseItem, ItemCounts>> GetArtists(InternalItemsQuery query);
+ QueryResult<Tuple<BaseItem, ItemCounts>> GetAlbumArtists(InternalItemsQuery query);
+ QueryResult<Tuple<BaseItem, ItemCounts>> GetAllArtists(InternalItemsQuery query);
+
+ int GetCount(InternalItemsQuery query);
+
+ void AddExternalSubtitleStreams(List<MediaStream> streams,
+ string videoPath,
+ string[] files);
+ }
+} \ No newline at end of file
diff --git a/MediaBrowser.Controller/Library/ILibraryMonitor.cs b/MediaBrowser.Controller/Library/ILibraryMonitor.cs
new file mode 100644
index 000000000..e965e47d6
--- /dev/null
+++ b/MediaBrowser.Controller/Library/ILibraryMonitor.cs
@@ -0,0 +1,43 @@
+using System;
+
+namespace MediaBrowser.Controller.Library
+{
+ public interface ILibraryMonitor : IDisposable
+ {
+ /// <summary>
+ /// Starts this instance.
+ /// </summary>
+ void Start();
+
+ /// <summary>
+ /// Stops this instance.
+ /// </summary>
+ void Stop();
+
+ /// <summary>
+ /// Reports the file system change beginning.
+ /// </summary>
+ /// <param name="path">The path.</param>
+ void ReportFileSystemChangeBeginning(string path);
+
+ /// <summary>
+ /// Reports the file system change complete.
+ /// </summary>
+ /// <param name="path">The path.</param>
+ /// <param name="refreshPath">if set to <c>true</c> [refresh path].</param>
+ void ReportFileSystemChangeComplete(string path, bool refreshPath);
+
+ /// <summary>
+ /// Reports the file system changed.
+ /// </summary>
+ /// <param name="path">The path.</param>
+ void ReportFileSystemChanged(string path);
+
+ /// <summary>
+ /// Determines whether [is path locked] [the specified path].
+ /// </summary>
+ /// <param name="path">The path.</param>
+ /// <returns><c>true</c> if [is path locked] [the specified path]; otherwise, <c>false</c>.</returns>
+ bool IsPathLocked(string path);
+ }
+} \ No newline at end of file
diff --git a/MediaBrowser.Controller/Library/ILibraryPostScanTask.cs b/MediaBrowser.Controller/Library/ILibraryPostScanTask.cs
new file mode 100644
index 000000000..694422907
--- /dev/null
+++ b/MediaBrowser.Controller/Library/ILibraryPostScanTask.cs
@@ -0,0 +1,20 @@
+using System;
+using System.Threading;
+using System.Threading.Tasks;
+
+namespace MediaBrowser.Controller.Library
+{
+ /// <summary>
+ /// An interface for tasks that run after the media library scan
+ /// </summary>
+ public interface ILibraryPostScanTask
+ {
+ /// <summary>
+ /// Runs the specified progress.
+ /// </summary>
+ /// <param name="progress">The progress.</param>
+ /// <param name="cancellationToken">The cancellation token.</param>
+ /// <returns>Task.</returns>
+ Task Run(IProgress<double> progress, CancellationToken cancellationToken);
+ }
+}
diff --git a/MediaBrowser.Controller/Library/ILiveStream.cs b/MediaBrowser.Controller/Library/ILiveStream.cs
new file mode 100644
index 000000000..e00da7340
--- /dev/null
+++ b/MediaBrowser.Controller/Library/ILiveStream.cs
@@ -0,0 +1,21 @@
+using System;
+using System.Collections.Generic;
+using System.Text;
+using System.Threading;
+using System.Threading.Tasks;
+using MediaBrowser.Model.Dto;
+
+namespace MediaBrowser.Controller.Library
+{
+ public interface ILiveStream
+ {
+ Task Open(CancellationToken openCancellationToken);
+ Task Close();
+ int ConsumerCount { get; set; }
+ string OriginalStreamId { get; set; }
+ string TunerHostId { get; }
+ bool EnableStreamSharing { get; }
+ MediaSourceInfo MediaSource { get; set; }
+ string UniqueId { get; }
+ }
+}
diff --git a/MediaBrowser.Controller/Library/IMediaSourceManager.cs b/MediaBrowser.Controller/Library/IMediaSourceManager.cs
new file mode 100644
index 000000000..8541c4fd9
--- /dev/null
+++ b/MediaBrowser.Controller/Library/IMediaSourceManager.cs
@@ -0,0 +1,100 @@
+using MediaBrowser.Controller.Entities;
+using MediaBrowser.Controller.Persistence;
+using MediaBrowser.Model.Dto;
+using MediaBrowser.Model.Entities;
+using MediaBrowser.Model.MediaInfo;
+using System;
+using System.Collections.Generic;
+using System.Threading;
+using System.Threading.Tasks;
+using System.IO;
+
+namespace MediaBrowser.Controller.Library
+{
+ public interface IMediaSourceManager
+ {
+ /// <summary>
+ /// Adds the parts.
+ /// </summary>
+ /// <param name="providers">The providers.</param>
+ void AddParts(IEnumerable<IMediaSourceProvider> providers);
+
+ /// <summary>
+ /// Gets the media streams.
+ /// </summary>
+ /// <param name="itemId">The item identifier.</param>
+ /// <returns>IEnumerable&lt;MediaStream&gt;.</returns>
+ List<MediaStream> GetMediaStreams(Guid itemId);
+ /// <summary>
+ /// Gets the media streams.
+ /// </summary>
+ /// <param name="mediaSourceId">The media source identifier.</param>
+ /// <returns>IEnumerable&lt;MediaStream&gt;.</returns>
+ List<MediaStream> GetMediaStreams(string mediaSourceId);
+ /// <summary>
+ /// Gets the media streams.
+ /// </summary>
+ /// <param name="query">The query.</param>
+ /// <returns>IEnumerable&lt;MediaStream&gt;.</returns>
+ List<MediaStream> GetMediaStreams(MediaStreamQuery query);
+
+ /// <summary>
+ /// Gets the playack media sources.
+ /// </summary>
+ Task<List<MediaSourceInfo>> GetPlayackMediaSources(BaseItem item, User user, bool allowMediaProbe, bool enablePathSubstitution, CancellationToken cancellationToken);
+
+ /// <summary>
+ /// Gets the static media sources.
+ /// </summary>
+ List<MediaSourceInfo> GetStaticMediaSources(BaseItem item, bool enablePathSubstitution, User user = null);
+
+ /// <summary>
+ /// Gets the static media source.
+ /// </summary>
+ Task<MediaSourceInfo> GetMediaSource(BaseItem item, string mediaSourceId, string liveStreamId, bool enablePathSubstitution, CancellationToken cancellationToken);
+
+ /// <summary>
+ /// Opens the media source.
+ /// </summary>
+ /// <param name="request">The request.</param>
+ /// <param name="cancellationToken">The cancellation token.</param>
+ /// <returns>Task&lt;MediaSourceInfo&gt;.</returns>
+ Task<LiveStreamResponse> OpenLiveStream(LiveStreamRequest request, CancellationToken cancellationToken);
+
+ Task<Tuple<LiveStreamResponse, IDirectStreamProvider>> OpenLiveStreamInternal(LiveStreamRequest request, CancellationToken cancellationToken);
+
+ /// <summary>
+ /// Gets the live stream.
+ /// </summary>
+ /// <param name="id">The identifier.</param>
+ /// <param name="cancellationToken">The cancellation token.</param>
+ /// <returns>Task&lt;MediaSourceInfo&gt;.</returns>
+ Task<MediaSourceInfo> GetLiveStream(string id, CancellationToken cancellationToken);
+
+ Task<Tuple<MediaSourceInfo, IDirectStreamProvider>> GetLiveStreamWithDirectStreamProvider(string id, CancellationToken cancellationToken);
+
+ /// <summary>
+ /// Closes the media source.
+ /// </summary>
+ /// <param name="id">The live stream identifier.</param>
+ /// <returns>Task.</returns>
+ Task CloseLiveStream(string id);
+
+ Task<MediaSourceInfo> GetLiveStreamMediaInfo(string id, CancellationToken cancellationToken);
+
+ bool SupportsDirectStream(string path, MediaProtocol protocol);
+
+ MediaProtocol GetPathProtocol(string path);
+
+ void SetDefaultAudioAndSubtitleStreamIndexes(BaseItem item, MediaSourceInfo source, User user);
+
+ Task AddMediaInfoWithProbe(MediaSourceInfo mediaSource, bool isAudio, string cacheKey, bool addProbeDelay, bool isLiveStream, CancellationToken cancellationToken);
+
+ Task<IDirectStreamProvider> GetDirectStreamProviderByUniqueId(string uniqueId, CancellationToken cancellationToken);
+ }
+
+ public interface IDirectStreamProvider
+ {
+ Task CopyToAsync(Stream stream, CancellationToken cancellationToken);
+ }
+}
diff --git a/MediaBrowser.Controller/Library/IMediaSourceProvider.cs b/MediaBrowser.Controller/Library/IMediaSourceProvider.cs
new file mode 100644
index 000000000..eec138532
--- /dev/null
+++ b/MediaBrowser.Controller/Library/IMediaSourceProvider.cs
@@ -0,0 +1,25 @@
+using MediaBrowser.Controller.Entities;
+using MediaBrowser.Model.Dto;
+using System.Collections.Generic;
+using System.Threading;
+using System.Threading.Tasks;
+using System;
+
+namespace MediaBrowser.Controller.Library
+{
+ public interface IMediaSourceProvider
+ {
+ /// <summary>
+ /// Gets the media sources.
+ /// </summary>
+ /// <param name="item">The item.</param>
+ /// <param name="cancellationToken">The cancellation token.</param>
+ /// <returns>Task&lt;IEnumerable&lt;MediaSourceInfo&gt;&gt;.</returns>
+ Task<IEnumerable<MediaSourceInfo>> GetMediaSources(BaseItem item, CancellationToken cancellationToken);
+
+ /// <summary>
+ /// Opens the media source.
+ /// </summary>
+ Task<ILiveStream> OpenMediaSource(string openToken, List<ILiveStream> currentLiveStreams, CancellationToken cancellationToken);
+ }
+}
diff --git a/MediaBrowser.Controller/Library/IMetadataFileSaver.cs b/MediaBrowser.Controller/Library/IMetadataFileSaver.cs
new file mode 100644
index 000000000..e66fbcbc8
--- /dev/null
+++ b/MediaBrowser.Controller/Library/IMetadataFileSaver.cs
@@ -0,0 +1,19 @@
+using MediaBrowser.Controller.Entities;
+
+namespace MediaBrowser.Controller.Library
+{
+ public interface IMetadataFileSaver : IMetadataSaver
+ {
+ /// <summary>
+ /// Gets the save path.
+ /// </summary>
+ /// <param name="item">The item.</param>
+ /// <returns>System.String.</returns>
+ string GetSavePath(BaseItem item);
+ }
+
+ public interface IConfigurableProvider
+ {
+ bool IsEnabled { get; }
+ }
+} \ No newline at end of file
diff --git a/MediaBrowser.Controller/Library/IMetadataSaver.cs b/MediaBrowser.Controller/Library/IMetadataSaver.cs
new file mode 100644
index 000000000..f71afa656
--- /dev/null
+++ b/MediaBrowser.Controller/Library/IMetadataSaver.cs
@@ -0,0 +1,33 @@
+using MediaBrowser.Controller.Entities;
+using System.Threading;
+
+namespace MediaBrowser.Controller.Library
+{
+ /// <summary>
+ /// Interface IMetadataSaver
+ /// </summary>
+ public interface IMetadataSaver
+ {
+ /// <summary>
+ /// Gets the name.
+ /// </summary>
+ /// <value>The name.</value>
+ string Name { get; }
+
+ /// <summary>
+ /// Determines whether [is enabled for] [the specified item].
+ /// </summary>
+ /// <param name="item">The item.</param>
+ /// <param name="updateType">Type of the update.</param>
+ /// <returns><c>true</c> if [is enabled for] [the specified item]; otherwise, <c>false</c>.</returns>
+ bool IsEnabledFor(BaseItem item, ItemUpdateType updateType);
+
+ /// <summary>
+ /// Saves the specified item.
+ /// </summary>
+ /// <param name="item">The item.</param>
+ /// <param name="cancellationToken">The cancellation token.</param>
+ /// <returns>Task.</returns>
+ void Save(BaseItem item, CancellationToken cancellationToken);
+ }
+}
diff --git a/MediaBrowser.Controller/Library/IMusicManager.cs b/MediaBrowser.Controller/Library/IMusicManager.cs
new file mode 100644
index 000000000..535e6df7e
--- /dev/null
+++ b/MediaBrowser.Controller/Library/IMusicManager.cs
@@ -0,0 +1,25 @@
+using MediaBrowser.Controller.Entities;
+using MediaBrowser.Controller.Entities.Audio;
+using System.Collections.Generic;
+using MediaBrowser.Controller.Dto;
+
+namespace MediaBrowser.Controller.Library
+{
+ public interface IMusicManager
+ {
+ /// <summary>
+ /// Gets the instant mix from song.
+ /// </summary>
+ List<BaseItem> GetInstantMixFromItem(BaseItem item, User user, DtoOptions dtoOptions);
+
+ /// <summary>
+ /// Gets the instant mix from artist.
+ /// </summary>
+ List<BaseItem> GetInstantMixFromArtist(MusicArtist artist, User user, DtoOptions dtoOptions);
+
+ /// <summary>
+ /// Gets the instant mix from genre.
+ /// </summary>
+ List<BaseItem> GetInstantMixFromGenres(IEnumerable<string> genres, User user, DtoOptions dtoOptions);
+ }
+}
diff --git a/MediaBrowser.Controller/Library/ISearchEngine.cs b/MediaBrowser.Controller/Library/ISearchEngine.cs
new file mode 100644
index 000000000..715f16407
--- /dev/null
+++ b/MediaBrowser.Controller/Library/ISearchEngine.cs
@@ -0,0 +1,18 @@
+using MediaBrowser.Model.Querying;
+using MediaBrowser.Model.Search;
+
+namespace MediaBrowser.Controller.Library
+{
+ /// <summary>
+ /// Interface ILibrarySearchEngine
+ /// </summary>
+ public interface ISearchEngine
+ {
+ /// <summary>
+ /// Gets the search hints.
+ /// </summary>
+ /// <param name="query">The query.</param>
+ /// <returns>Task{IEnumerable{SearchHintInfo}}.</returns>
+ QueryResult<SearchHintInfo> GetSearchHints(SearchQuery query);
+ }
+}
diff --git a/MediaBrowser.Controller/Library/IUserDataManager.cs b/MediaBrowser.Controller/Library/IUserDataManager.cs
new file mode 100644
index 000000000..11d77f81a
--- /dev/null
+++ b/MediaBrowser.Controller/Library/IUserDataManager.cs
@@ -0,0 +1,67 @@
+using System.Collections.Generic;
+using MediaBrowser.Controller.Dto;
+using MediaBrowser.Controller.Entities;
+using MediaBrowser.Model.Dto;
+using MediaBrowser.Model.Entities;
+using System;
+using System.Threading;
+using MediaBrowser.Model.Querying;
+
+namespace MediaBrowser.Controller.Library
+{
+ /// <summary>
+ /// Interface IUserDataManager
+ /// </summary>
+ public interface IUserDataManager
+ {
+ /// <summary>
+ /// Occurs when [user data saved].
+ /// </summary>
+ event EventHandler<UserDataSaveEventArgs> UserDataSaved;
+
+ /// <summary>
+ /// Saves the user data.
+ /// </summary>
+ /// <param name="userId">The user id.</param>
+ /// <param name="item">The item.</param>
+ /// <param name="userData">The user data.</param>
+ /// <param name="reason">The reason.</param>
+ /// <param name="cancellationToken">The cancellation token.</param>
+ /// <returns>Task.</returns>
+ void SaveUserData(Guid userId, BaseItem item, UserItemData userData, UserDataSaveReason reason, CancellationToken cancellationToken);
+ void SaveUserData(User userId, BaseItem item, UserItemData userData, UserDataSaveReason reason, CancellationToken cancellationToken);
+
+ UserItemData GetUserData(User user, BaseItem item);
+
+ UserItemData GetUserData(string userId, BaseItem item);
+ UserItemData GetUserData(Guid userId, BaseItem item);
+
+ /// <summary>
+ /// Gets the user data dto.
+ /// </summary>
+ UserItemDataDto GetUserDataDto(BaseItem item, User user);
+
+ UserItemDataDto GetUserDataDto(BaseItem item, BaseItemDto itemDto, User user, DtoOptions dto_options);
+
+ /// <summary>
+ /// Get all user data for the given user
+ /// </summary>
+ /// <param name="userId"></param>
+ /// <returns></returns>
+ List<UserItemData> GetAllUserData(Guid userId);
+
+ /// <summary>
+ /// Save the all provided user data for the given user
+ /// </summary>
+ /// <param name="userId"></param>
+ /// <param name="userData"></param>
+ /// <param name="cancellationToken"></param>
+ /// <returns></returns>
+ void SaveAllUserData(Guid userId, UserItemData[] userData, CancellationToken cancellationToken);
+
+ /// <summary>
+ /// Updates playstate for an item and returns true or false indicating if it was played to completion
+ /// </summary>
+ bool UpdatePlayState(BaseItem item, UserItemData data, long? positionTicks);
+ }
+}
diff --git a/MediaBrowser.Controller/Library/IUserManager.cs b/MediaBrowser.Controller/Library/IUserManager.cs
new file mode 100644
index 000000000..d29b164ef
--- /dev/null
+++ b/MediaBrowser.Controller/Library/IUserManager.cs
@@ -0,0 +1,207 @@
+using MediaBrowser.Controller.Entities;
+using MediaBrowser.Model.Configuration;
+using MediaBrowser.Model.Dto;
+using MediaBrowser.Model.Events;
+using System;
+using System.Collections.Generic;
+using System.Threading;
+using System.Threading.Tasks;
+using MediaBrowser.Model.Users;
+using MediaBrowser.Controller.Authentication;
+
+namespace MediaBrowser.Controller.Library
+{
+ /// <summary>
+ /// Interface IUserManager
+ /// </summary>
+ public interface IUserManager
+ {
+ /// <summary>
+ /// Gets the users.
+ /// </summary>
+ /// <value>The users.</value>
+ IEnumerable<User> Users { get; }
+
+ /// <summary>
+ /// Occurs when [user updated].
+ /// </summary>
+ event EventHandler<GenericEventArgs<User>> UserUpdated;
+
+ /// <summary>
+ /// Occurs when [user deleted].
+ /// </summary>
+ event EventHandler<GenericEventArgs<User>> UserDeleted;
+
+ event EventHandler<GenericEventArgs<User>> UserCreated;
+ event EventHandler<GenericEventArgs<User>> UserPolicyUpdated;
+ event EventHandler<GenericEventArgs<User>> UserConfigurationUpdated;
+ event EventHandler<GenericEventArgs<User>> UserPasswordChanged;
+ event EventHandler<GenericEventArgs<User>> UserLockedOut;
+
+ /// <summary>
+ /// Gets a User by Id
+ /// </summary>
+ /// <param name="id">The id.</param>
+ /// <returns>User.</returns>
+ /// <exception cref="System.ArgumentNullException"></exception>
+ User GetUserById(Guid id);
+
+ /// <summary>
+ /// Gets the user by identifier.
+ /// </summary>
+ /// <param name="id">The identifier.</param>
+ /// <returns>User.</returns>
+ User GetUserById(string id);
+
+ /// <summary>
+ /// Gets the name of the user by.
+ /// </summary>
+ /// <param name="name">The name.</param>
+ /// <returns>User.</returns>
+ User GetUserByName(string name);
+
+ /// <summary>
+ /// Refreshes metadata for each user
+ /// </summary>
+ /// <param name="cancellationToken">The cancellation token.</param>
+ /// <returns>Task.</returns>
+ Task RefreshUsersMetadata(CancellationToken cancellationToken);
+
+ /// <summary>
+ /// Renames the user.
+ /// </summary>
+ /// <param name="user">The user.</param>
+ /// <param name="newName">The new name.</param>
+ /// <returns>Task.</returns>
+ /// <exception cref="System.ArgumentNullException">user</exception>
+ /// <exception cref="System.ArgumentException"></exception>
+ Task RenameUser(User user, string newName);
+
+ /// <summary>
+ /// Updates the user.
+ /// </summary>
+ /// <param name="user">The user.</param>
+ /// <exception cref="System.ArgumentNullException">user</exception>
+ /// <exception cref="System.ArgumentException"></exception>
+ void UpdateUser(User user);
+
+ /// <summary>
+ /// Creates the user.
+ /// </summary>
+ /// <param name="name">The name.</param>
+ /// <returns>User.</returns>
+ /// <exception cref="System.ArgumentNullException">name</exception>
+ /// <exception cref="System.ArgumentException"></exception>
+ Task<User> CreateUser(string name);
+
+ /// <summary>
+ /// Deletes the user.
+ /// </summary>
+ /// <param name="user">The user.</param>
+ /// <returns>Task.</returns>
+ /// <exception cref="System.ArgumentNullException">user</exception>
+ /// <exception cref="System.ArgumentException"></exception>
+ Task DeleteUser(User user);
+
+ /// <summary>
+ /// Resets the password.
+ /// </summary>
+ /// <param name="user">The user.</param>
+ /// <returns>Task.</returns>
+ Task ResetPassword(User user);
+
+ /// <summary>
+ /// Gets the offline user dto.
+ /// </summary>
+ /// <param name="user">The user.</param>
+ /// <returns>UserDto.</returns>
+ UserDto GetOfflineUserDto(User user);
+
+ /// <summary>
+ /// Resets the easy password.
+ /// </summary>
+ /// <param name="user">The user.</param>
+ /// <returns>Task.</returns>
+ void ResetEasyPassword(User user);
+
+ /// <summary>
+ /// Changes the password.
+ /// </summary>
+ Task ChangePassword(User user, string newPassword);
+
+ /// <summary>
+ /// Changes the easy password.
+ /// </summary>
+ void ChangeEasyPassword(User user, string newPassword, string newPasswordSha1);
+
+ /// <summary>
+ /// Gets the user dto.
+ /// </summary>
+ /// <param name="user">The user.</param>
+ /// <param name="remoteEndPoint">The remote end point.</param>
+ /// <returns>UserDto.</returns>
+ UserDto GetUserDto(User user, string remoteEndPoint = null);
+
+ /// <summary>
+ /// Authenticates the user.
+ /// </summary>
+ Task<User> AuthenticateUser(string username, string password, string passwordSha1, string remoteEndPoint, bool isUserSession);
+
+ /// <summary>
+ /// Starts the forgot password process.
+ /// </summary>
+ /// <param name="enteredUsername">The entered username.</param>
+ /// <param name="isInNetwork">if set to <c>true</c> [is in network].</param>
+ /// <returns>ForgotPasswordResult.</returns>
+ Task<ForgotPasswordResult> StartForgotPasswordProcess(string enteredUsername, bool isInNetwork);
+
+ /// <summary>
+ /// Redeems the password reset pin.
+ /// </summary>
+ /// <param name="pin">The pin.</param>
+ /// <returns><c>true</c> if XXXX, <c>false</c> otherwise.</returns>
+ Task<PinRedeemResult> RedeemPasswordResetPin(string pin);
+
+ /// <summary>
+ /// Gets the user policy.
+ /// </summary>
+ /// <param name="user">The user.</param>
+ /// <returns>UserPolicy.</returns>
+ UserPolicy GetUserPolicy(User user);
+
+ /// <summary>
+ /// Gets the user configuration.
+ /// </summary>
+ /// <param name="user">The user.</param>
+ /// <returns>UserConfiguration.</returns>
+ UserConfiguration GetUserConfiguration(User user);
+
+ /// <summary>
+ /// Updates the configuration.
+ /// </summary>
+ /// <param name="userId">The user identifier.</param>
+ /// <param name="newConfiguration">The new configuration.</param>
+ /// <returns>Task.</returns>
+ void UpdateConfiguration(Guid userId, UserConfiguration newConfiguration);
+
+ void UpdateConfiguration(User user, UserConfiguration newConfiguration);
+
+ /// <summary>
+ /// Updates the user policy.
+ /// </summary>
+ /// <param name="userId">The user identifier.</param>
+ /// <param name="userPolicy">The user policy.</param>
+ void UpdateUserPolicy(Guid userId, UserPolicy userPolicy);
+
+ /// <summary>
+ /// Makes the valid username.
+ /// </summary>
+ /// <param name="username">The username.</param>
+ /// <returns>System.String.</returns>
+ string MakeValidUsername(string username);
+
+ void AddParts(IEnumerable<IAuthenticationProvider> authenticationProviders);
+
+ NameIdPair[] GetAuthenticationProviders();
+ }
+}
diff --git a/MediaBrowser.Controller/Library/IUserViewManager.cs b/MediaBrowser.Controller/Library/IUserViewManager.cs
new file mode 100644
index 000000000..f4649777c
--- /dev/null
+++ b/MediaBrowser.Controller/Library/IUserViewManager.cs
@@ -0,0 +1,19 @@
+using MediaBrowser.Controller.Entities;
+using MediaBrowser.Model.Library;
+using MediaBrowser.Model.Querying;
+using System;
+using System.Collections.Generic;
+using System.Threading;
+using System.Threading.Tasks;
+using MediaBrowser.Controller.Dto;
+
+namespace MediaBrowser.Controller.Library
+{
+ public interface IUserViewManager
+ {
+ Folder[] GetUserViews(UserViewQuery query);
+ UserView GetUserSubView(Guid parentId, string type, string localizationKey, string sortName);
+
+ List<Tuple<BaseItem, List<BaseItem>>> GetLatestItems(LatestItemsQuery request, DtoOptions options);
+ }
+}
diff --git a/MediaBrowser.Controller/Library/IntroInfo.cs b/MediaBrowser.Controller/Library/IntroInfo.cs
new file mode 100644
index 000000000..d0e61d0f0
--- /dev/null
+++ b/MediaBrowser.Controller/Library/IntroInfo.cs
@@ -0,0 +1,19 @@
+using System;
+
+namespace MediaBrowser.Controller.Library
+{
+ public class IntroInfo
+ {
+ /// <summary>
+ /// Gets or sets the path.
+ /// </summary>
+ /// <value>The path.</value>
+ public string Path { get; set; }
+
+ /// <summary>
+ /// Gets or sets the item id.
+ /// </summary>
+ /// <value>The item id.</value>
+ public Guid? ItemId { get; set; }
+ }
+} \ No newline at end of file
diff --git a/MediaBrowser.Controller/Library/ItemChangeEventArgs.cs b/MediaBrowser.Controller/Library/ItemChangeEventArgs.cs
new file mode 100644
index 000000000..e671490d3
--- /dev/null
+++ b/MediaBrowser.Controller/Library/ItemChangeEventArgs.cs
@@ -0,0 +1,24 @@
+using MediaBrowser.Controller.Entities;
+
+namespace MediaBrowser.Controller.Library
+{
+ /// <summary>
+ /// Class ItemChangeEventArgs
+ /// </summary>
+ public class ItemChangeEventArgs
+ {
+ /// <summary>
+ /// Gets or sets the item.
+ /// </summary>
+ /// <value>The item.</value>
+ public BaseItem Item { get; set; }
+
+ public BaseItem Parent { get; set; }
+
+ /// <summary>
+ /// Gets or sets the item.
+ /// </summary>
+ /// <value>The item.</value>
+ public ItemUpdateType UpdateReason { get; set; }
+ }
+}
diff --git a/MediaBrowser.Controller/Library/ItemResolveArgs.cs b/MediaBrowser.Controller/Library/ItemResolveArgs.cs
new file mode 100644
index 000000000..7197425f3
--- /dev/null
+++ b/MediaBrowser.Controller/Library/ItemResolveArgs.cs
@@ -0,0 +1,281 @@
+using MediaBrowser.Controller.Entities;
+using MediaBrowser.Controller.Providers;
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Linq;
+using MediaBrowser.Controller.Configuration;
+using MediaBrowser.Controller.IO;
+using MediaBrowser.Model.Configuration;
+using MediaBrowser.Model.IO;
+
+namespace MediaBrowser.Controller.Library
+{
+ /// <summary>
+ /// These are arguments relating to the file system that are collected once and then referred to
+ /// whenever needed. Primarily for entity resolution.
+ /// </summary>
+ public class ItemResolveArgs : EventArgs
+ {
+ /// <summary>
+ /// The _app paths
+ /// </summary>
+ private readonly IServerApplicationPaths _appPaths;
+
+ public IDirectoryService DirectoryService { get; private set; }
+
+ /// <summary>
+ /// Initializes a new instance of the <see cref="ItemResolveArgs" /> class.
+ /// </summary>
+ /// <param name="appPaths">The app paths.</param>
+ /// <param name="directoryService">The directory service.</param>
+ public ItemResolveArgs(IServerApplicationPaths appPaths, IDirectoryService directoryService)
+ {
+ _appPaths = appPaths;
+ DirectoryService = directoryService;
+ }
+
+ /// <summary>
+ /// Gets the file system children.
+ /// </summary>
+ /// <value>The file system children.</value>
+ public FileSystemMetadata[] FileSystemChildren { get; set; }
+
+ public LibraryOptions LibraryOptions { get; set; }
+
+ public LibraryOptions GetLibraryOptions()
+ {
+ return LibraryOptions ?? (LibraryOptions = (Parent == null ? new LibraryOptions() : BaseItem.LibraryManager.GetLibraryOptions(Parent)));
+ }
+
+ /// <summary>
+ /// Gets or sets the parent.
+ /// </summary>
+ /// <value>The parent.</value>
+ public Folder Parent { get; set; }
+
+ /// <summary>
+ /// Gets or sets the file info.
+ /// </summary>
+ /// <value>The file info.</value>
+ public FileSystemMetadata FileInfo { get; set; }
+
+ /// <summary>
+ /// Gets or sets the path.
+ /// </summary>
+ /// <value>The path.</value>
+ public string Path { get; set; }
+
+ /// <summary>
+ /// Gets a value indicating whether this instance is directory.
+ /// </summary>
+ /// <value><c>true</c> if this instance is directory; otherwise, <c>false</c>.</value>
+ public bool IsDirectory
+ {
+ get
+ {
+ return FileInfo.IsDirectory;
+ }
+ }
+
+ /// <summary>
+ /// Gets a value indicating whether this instance is vf.
+ /// </summary>
+ /// <value><c>true</c> if this instance is vf; otherwise, <c>false</c>.</value>
+ public bool IsVf
+ {
+ // we should be considered a virtual folder if we are a child of one of the children of the system root folder.
+ // this is a bit of a trick to determine that... the directory name of a sub-child of the root will start with
+ // the root but not be equal to it
+ get
+ {
+ if (!IsDirectory)
+ {
+ return false;
+ }
+
+ var parentDir = BaseItem.FileSystem.GetDirectoryName(Path) ?? string.Empty;
+
+ return parentDir.Length > _appPaths.RootFolderPath.Length
+ && parentDir.StartsWith(_appPaths.RootFolderPath, StringComparison.OrdinalIgnoreCase);
+
+ }
+ }
+
+ /// <summary>
+ /// Gets a value indicating whether this instance is physical root.
+ /// </summary>
+ /// <value><c>true</c> if this instance is physical root; otherwise, <c>false</c>.</value>
+ public bool IsPhysicalRoot
+ {
+ get
+ {
+ return IsDirectory && BaseItem.FileSystem.AreEqual(Path, _appPaths.RootFolderPath);
+ }
+ }
+
+ /// <summary>
+ /// Gets or sets the additional locations.
+ /// </summary>
+ /// <value>The additional locations.</value>
+ private List<string> AdditionalLocations { get; set; }
+
+ public bool HasParent<T>()
+ where T : Folder
+ {
+ var parent = Parent;
+
+ if (parent != null)
+ {
+ var item = parent as T;
+
+ // Just in case the user decided to nest episodes.
+ // Not officially supported but in some cases we can handle it.
+ if (item == null)
+ {
+ var parents = parent.GetParents();
+ foreach (var currentParent in parents)
+ {
+ if (currentParent is T)
+ {
+ return true;
+ }
+ }
+ }
+
+ return item != null;
+
+ }
+ return false;
+ }
+
+ /// <summary>
+ /// Adds the additional location.
+ /// </summary>
+ /// <param name="path">The path.</param>
+ /// <exception cref="System.ArgumentNullException"></exception>
+ public void AddAdditionalLocation(string path)
+ {
+ if (string.IsNullOrEmpty(path))
+ {
+ throw new ArgumentNullException();
+ }
+
+ if (AdditionalLocations == null)
+ {
+ AdditionalLocations = new List<string>();
+ }
+
+ AdditionalLocations.Add(path);
+ }
+
+ /// <summary>
+ /// Gets the physical locations.
+ /// </summary>
+ /// <value>The physical locations.</value>
+ public string[] PhysicalLocations
+ {
+ get
+ {
+ var paths = string.IsNullOrEmpty(Path) ? new string[] { } : new[] { Path };
+ return AdditionalLocations == null ? paths : paths.Concat(AdditionalLocations).ToArray();
+ }
+ }
+
+ /// <summary>
+ /// Gets the name of the file system entry by.
+ /// </summary>
+ /// <param name="name">The name.</param>
+ /// <returns>FileSystemInfo.</returns>
+ /// <exception cref="System.ArgumentNullException"></exception>
+ public FileSystemMetadata GetFileSystemEntryByName(string name)
+ {
+ if (string.IsNullOrEmpty(name))
+ {
+ throw new ArgumentNullException();
+ }
+
+ return GetFileSystemEntryByPath(System.IO.Path.Combine(Path, name));
+ }
+
+ /// <summary>
+ /// Gets the file system entry by path.
+ /// </summary>
+ /// <param name="path">The path.</param>
+ /// <returns>FileSystemInfo.</returns>
+ /// <exception cref="System.ArgumentNullException"></exception>
+ public FileSystemMetadata GetFileSystemEntryByPath(string path)
+ {
+ if (string.IsNullOrEmpty(path))
+ {
+ throw new ArgumentNullException();
+ }
+
+ foreach (var file in FileSystemChildren)
+ {
+ if (string.Equals(file.FullName, path, StringComparison.Ordinal))
+ {
+ return file;
+ }
+ }
+
+ return null;
+ }
+
+ /// <summary>
+ /// Determines whether [contains file system entry by name] [the specified name].
+ /// </summary>
+ /// <param name="name">The name.</param>
+ /// <returns><c>true</c> if [contains file system entry by name] [the specified name]; otherwise, <c>false</c>.</returns>
+ public bool ContainsFileSystemEntryByName(string name)
+ {
+ return GetFileSystemEntryByName(name) != null;
+ }
+
+ public string GetCollectionType()
+ {
+ return CollectionType;
+ }
+
+ public string CollectionType { get; set; }
+
+ #region Equality Overrides
+
+ /// <summary>
+ /// Determines whether the specified <see cref="System.Object" /> is equal to this instance.
+ /// </summary>
+ /// <param name="obj">The object to compare with the current object.</param>
+ /// <returns><c>true</c> if the specified <see cref="System.Object" /> is equal to this instance; otherwise, <c>false</c>.</returns>
+ public override bool Equals(object obj)
+ {
+ return Equals(obj as ItemResolveArgs);
+ }
+
+ /// <summary>
+ /// Returns a hash code for this instance.
+ /// </summary>
+ /// <returns>A hash code for this instance, suitable for use in hashing algorithms and data structures like a hash table.</returns>
+ public override int GetHashCode()
+ {
+ return Path.GetHashCode();
+ }
+
+ /// <summary>
+ /// Equalses the specified args.
+ /// </summary>
+ /// <param name="args">The args.</param>
+ /// <returns><c>true</c> if XXXX, <c>false</c> otherwise</returns>
+ protected bool Equals(ItemResolveArgs args)
+ {
+ if (args != null)
+ {
+ if (args.Path == null && Path == null) return true;
+ return args.Path != null && BaseItem.FileSystem.AreEqual(args.Path, Path);
+ }
+ return false;
+ }
+
+ #endregion
+ }
+
+}
diff --git a/MediaBrowser.Controller/Library/ItemUpdateType.cs b/MediaBrowser.Controller/Library/ItemUpdateType.cs
new file mode 100644
index 000000000..cf6263356
--- /dev/null
+++ b/MediaBrowser.Controller/Library/ItemUpdateType.cs
@@ -0,0 +1,14 @@
+using System;
+
+namespace MediaBrowser.Controller.Library
+{
+ [Flags]
+ public enum ItemUpdateType
+ {
+ None = 1,
+ MetadataImport = 2,
+ ImageUpdate = 4,
+ MetadataDownload = 8,
+ MetadataEdit = 16
+ }
+}
diff --git a/MediaBrowser.Controller/Library/LibraryManagerExtensions.cs b/MediaBrowser.Controller/Library/LibraryManagerExtensions.cs
new file mode 100644
index 000000000..ec69bea6e
--- /dev/null
+++ b/MediaBrowser.Controller/Library/LibraryManagerExtensions.cs
@@ -0,0 +1,13 @@
+using System;
+using MediaBrowser.Controller.Entities;
+
+namespace MediaBrowser.Controller.Library
+{
+ public static class LibraryManagerExtensions
+ {
+ public static BaseItem GetItemById(this ILibraryManager manager, string id)
+ {
+ return manager.GetItemById(new Guid(id));
+ }
+ }
+} \ No newline at end of file
diff --git a/MediaBrowser.Controller/Library/MetadataConfigurationStore.cs b/MediaBrowser.Controller/Library/MetadataConfigurationStore.cs
new file mode 100644
index 000000000..dc2fa0f99
--- /dev/null
+++ b/MediaBrowser.Controller/Library/MetadataConfigurationStore.cs
@@ -0,0 +1,29 @@
+using MediaBrowser.Common.Configuration;
+using MediaBrowser.Model.Configuration;
+using System.Collections.Generic;
+
+namespace MediaBrowser.Controller.Library
+{
+ public class MetadataConfigurationStore : IConfigurationFactory
+ {
+ public IEnumerable<ConfigurationStore> GetConfigurations()
+ {
+ return new ConfigurationStore[]
+ {
+ new ConfigurationStore
+ {
+ Key = "metadata",
+ ConfigurationType = typeof(MetadataConfiguration)
+ }
+ };
+ }
+ }
+
+ public static class MetadataConfigurationExtensions
+ {
+ public static MetadataConfiguration GetMetadataConfiguration(this IConfigurationManager config)
+ {
+ return config.GetConfiguration<MetadataConfiguration>("metadata");
+ }
+ }
+}
diff --git a/MediaBrowser.Controller/Library/NameExtensions.cs b/MediaBrowser.Controller/Library/NameExtensions.cs
new file mode 100644
index 000000000..bab334a6d
--- /dev/null
+++ b/MediaBrowser.Controller/Library/NameExtensions.cs
@@ -0,0 +1,26 @@
+using System;
+using System.Collections.Generic;
+using MediaBrowser.Controller.Extensions;
+using MediaBrowser.Model.Extensions;
+
+namespace MediaBrowser.Controller.Library
+{
+ public static class NameExtensions
+ {
+ private static string RemoveDiacritics(string name)
+ {
+ if (name == null)
+ {
+ return string.Empty;
+ }
+
+ //return name;
+ return name.RemoveDiacritics();
+ }
+
+ public static IEnumerable<string> DistinctNames(this IEnumerable<string> names)
+ {
+ return names.DistinctBy(RemoveDiacritics, StringComparer.OrdinalIgnoreCase);
+ }
+ }
+}
diff --git a/MediaBrowser.Controller/Library/PlaybackProgressEventArgs.cs b/MediaBrowser.Controller/Library/PlaybackProgressEventArgs.cs
new file mode 100644
index 000000000..00d9932a7
--- /dev/null
+++ b/MediaBrowser.Controller/Library/PlaybackProgressEventArgs.cs
@@ -0,0 +1,34 @@
+using MediaBrowser.Controller.Entities;
+using MediaBrowser.Model.Dto;
+using System;
+using System.Collections.Generic;
+using MediaBrowser.Controller.Session;
+
+namespace MediaBrowser.Controller.Library
+{
+ /// <summary>
+ /// Holds information about a playback progress event
+ /// </summary>
+ public class PlaybackProgressEventArgs : EventArgs
+ {
+ public List<User> Users { get; set; }
+ public long? PlaybackPositionTicks { get; set; }
+ public BaseItem Item { get; set; }
+ public BaseItemDto MediaInfo { get; set; }
+ public string MediaSourceId { get; set; }
+ public bool IsPaused { get; set; }
+ public bool IsAutomated { get; set; }
+
+ public string DeviceId { get; set; }
+ public string DeviceName { get; set; }
+ public string ClientName { get; set; }
+
+ public string PlaySessionId { get; set; }
+ public SessionInfo Session { get; set; }
+
+ public PlaybackProgressEventArgs()
+ {
+ Users = new List<User>();
+ }
+ }
+}
diff --git a/MediaBrowser.Controller/Library/PlaybackStopEventArgs.cs b/MediaBrowser.Controller/Library/PlaybackStopEventArgs.cs
new file mode 100644
index 000000000..b0f6799fc
--- /dev/null
+++ b/MediaBrowser.Controller/Library/PlaybackStopEventArgs.cs
@@ -0,0 +1,11 @@
+namespace MediaBrowser.Controller.Library
+{
+ public class PlaybackStopEventArgs : PlaybackProgressEventArgs
+ {
+ /// <summary>
+ /// Gets or sets a value indicating whether [played to completion].
+ /// </summary>
+ /// <value><c>true</c> if [played to completion]; otherwise, <c>false</c>.</value>
+ public bool PlayedToCompletion { get; set; }
+ }
+} \ No newline at end of file
diff --git a/MediaBrowser.Controller/Library/Profiler.cs b/MediaBrowser.Controller/Library/Profiler.cs
new file mode 100644
index 000000000..3957c3020
--- /dev/null
+++ b/MediaBrowser.Controller/Library/Profiler.cs
@@ -0,0 +1,76 @@
+using MediaBrowser.Model.Logging;
+using System;
+using System.Diagnostics;
+
+namespace MediaBrowser.Controller.Library
+{
+ /// <summary>
+ /// Class Profiler
+ /// </summary>
+ public class Profiler : IDisposable
+ {
+ /// <summary>
+ /// The name
+ /// </summary>
+ readonly string _name;
+ /// <summary>
+ /// The stopwatch
+ /// </summary>
+ readonly Stopwatch _stopwatch;
+
+ /// <summary>
+ /// The _logger
+ /// </summary>
+ private readonly ILogger _logger;
+
+ /// <summary>
+ /// Initializes a new instance of the <see cref="Profiler" /> class.
+ /// </summary>
+ /// <param name="name">The name.</param>
+ /// <param name="logger">The logger.</param>
+ public Profiler(string name, ILogger logger)
+ {
+ this._name = name;
+
+ _logger = logger;
+
+ _stopwatch = new Stopwatch();
+ _stopwatch.Start();
+ }
+ #region IDisposable Members
+
+ /// <summary>
+ /// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources.
+ /// </summary>
+ public void Dispose()
+ {
+ Dispose(true);
+ }
+
+ /// <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)
+ {
+ _stopwatch.Stop();
+ string message;
+ if (_stopwatch.ElapsedMilliseconds > 300000)
+ {
+ message = string.Format("{0} took {1} minutes.",
+ _name, ((float)_stopwatch.ElapsedMilliseconds / 60000).ToString("F"));
+ }
+ else
+ {
+ message = string.Format("{0} took {1} seconds.",
+ _name, ((float)_stopwatch.ElapsedMilliseconds / 1000).ToString("#0.000"));
+ }
+ _logger.Info(message);
+ }
+ }
+
+ #endregion
+ }
+}
diff --git a/MediaBrowser.Controller/Library/SearchHintInfo.cs b/MediaBrowser.Controller/Library/SearchHintInfo.cs
new file mode 100644
index 000000000..f832811c2
--- /dev/null
+++ b/MediaBrowser.Controller/Library/SearchHintInfo.cs
@@ -0,0 +1,22 @@
+using MediaBrowser.Controller.Entities;
+
+namespace MediaBrowser.Controller.Library
+{
+ /// <summary>
+ /// Class SearchHintInfo
+ /// </summary>
+ public class SearchHintInfo
+ {
+ /// <summary>
+ /// Gets or sets the item.
+ /// </summary>
+ /// <value>The item.</value>
+ public BaseItem Item { get; set; }
+
+ /// <summary>
+ /// Gets or sets the matched term.
+ /// </summary>
+ /// <value>The matched term.</value>
+ public string MatchedTerm { get; set; }
+ }
+}
diff --git a/MediaBrowser.Controller/Library/TVUtils.cs b/MediaBrowser.Controller/Library/TVUtils.cs
new file mode 100644
index 000000000..dc95ba112
--- /dev/null
+++ b/MediaBrowser.Controller/Library/TVUtils.cs
@@ -0,0 +1,59 @@
+using System;
+using System.Collections.Generic;
+
+namespace MediaBrowser.Controller.Library
+{
+ /// <summary>
+ /// Class TVUtils
+ /// </summary>
+ public static class TVUtils
+ {
+ /// <summary>
+ /// The TVDB API key
+ /// </summary>
+ public static readonly string TvdbApiKey = "B89CE93890E9419B";
+ public static readonly string TvdbBaseUrl = "https://www.thetvdb.com/";
+ /// <summary>
+ /// The banner URL
+ /// </summary>
+ public static readonly string BannerUrl = TvdbBaseUrl + "banners/";
+
+ /// <summary>
+ /// Gets the air days.
+ /// </summary>
+ /// <param name="day">The day.</param>
+ /// <returns>List{DayOfWeek}.</returns>
+ public static DayOfWeek[] GetAirDays(string day)
+ {
+ if (!string.IsNullOrEmpty(day))
+ {
+ if (string.Equals(day, "Daily", StringComparison.OrdinalIgnoreCase))
+ {
+ return new DayOfWeek[]
+ {
+ DayOfWeek.Sunday,
+ DayOfWeek.Monday,
+ DayOfWeek.Tuesday,
+ DayOfWeek.Wednesday,
+ DayOfWeek.Thursday,
+ DayOfWeek.Friday,
+ DayOfWeek.Saturday
+ };
+ }
+
+ DayOfWeek value;
+
+ if (Enum.TryParse(day, true, out value))
+ {
+ return new DayOfWeek[]
+ {
+ value
+ };
+ }
+
+ return new DayOfWeek[]{};
+ }
+ return null;
+ }
+ }
+}
diff --git a/MediaBrowser.Controller/Library/UserDataSaveEventArgs.cs b/MediaBrowser.Controller/Library/UserDataSaveEventArgs.cs
new file mode 100644
index 000000000..d921a7077
--- /dev/null
+++ b/MediaBrowser.Controller/Library/UserDataSaveEventArgs.cs
@@ -0,0 +1,39 @@
+using MediaBrowser.Controller.Entities;
+using MediaBrowser.Model.Entities;
+using System;
+using System.Collections.Generic;
+
+namespace MediaBrowser.Controller.Library
+{
+ /// <summary>
+ /// Class UserDataSaveEventArgs
+ /// </summary>
+ public class UserDataSaveEventArgs : EventArgs
+ {
+ /// <summary>
+ /// Gets or sets the user id.
+ /// </summary>
+ /// <value>The user id.</value>
+ public Guid UserId { get; set; }
+
+ public List<string> Keys { get; set; }
+
+ /// <summary>
+ /// Gets or sets the save reason.
+ /// </summary>
+ /// <value>The save reason.</value>
+ public UserDataSaveReason SaveReason { get; set; }
+
+ /// <summary>
+ /// Gets or sets the user data.
+ /// </summary>
+ /// <value>The user data.</value>
+ public UserItemData UserData { get; set; }
+
+ /// <summary>
+ /// Gets or sets the item.
+ /// </summary>
+ /// <value>The item.</value>
+ public BaseItem Item { get; set; }
+ }
+}