mirror of
https://github.com/jellyfin/jellyfin.git
synced 2026-06-15 12:10:47 +01:00
Pushing missing changes
This commit is contained in:
@@ -1,386 +1,599 @@
|
||||
using MediaBrowser.Common.Kernel;
|
||||
using MediaBrowser.Common.Logging;
|
||||
using MediaBrowser.Controller.Entities;
|
||||
using MediaBrowser.Controller.Entities.TV;
|
||||
using MediaBrowser.Controller.IO;
|
||||
using MediaBrowser.Controller.Library;
|
||||
using MediaBrowser.Controller.Providers;
|
||||
using MediaBrowser.Controller.Resolvers;
|
||||
using MediaBrowser.Controller.Weather;
|
||||
using MediaBrowser.Model.Authentication;
|
||||
using MediaBrowser.Model.Configuration;
|
||||
using MediaBrowser.Model.Progress;
|
||||
using MediaBrowser.Common.Extensions;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel.Composition;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using System.Security.Cryptography;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace MediaBrowser.Controller
|
||||
{
|
||||
public class Kernel : BaseKernel<ServerConfiguration, ServerApplicationPaths>
|
||||
{
|
||||
#region Events
|
||||
/// <summary>
|
||||
/// Fires whenever any validation routine adds or removes items. The added and removed items are properties of the args.
|
||||
/// *** Will fire asynchronously. ***
|
||||
/// </summary>
|
||||
public event EventHandler<ChildrenChangedEventArgs> LibraryChanged;
|
||||
public void OnLibraryChanged(ChildrenChangedEventArgs args)
|
||||
{
|
||||
if (LibraryChanged != null)
|
||||
{
|
||||
Task.Run(() => LibraryChanged(this, args));
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
public static Kernel Instance { get; private set; }
|
||||
|
||||
public ItemController ItemController { get; private set; }
|
||||
|
||||
public IEnumerable<User> Users { get; private set; }
|
||||
public Folder RootFolder { get; private set; }
|
||||
|
||||
private DirectoryWatchers DirectoryWatchers { get; set; }
|
||||
|
||||
private string MediaRootFolderPath
|
||||
{
|
||||
get
|
||||
{
|
||||
return ApplicationPaths.RootFolderPath;
|
||||
}
|
||||
}
|
||||
|
||||
public override KernelContext KernelContext
|
||||
{
|
||||
get { return KernelContext.Server; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the list of currently registered weather prvoiders
|
||||
/// </summary>
|
||||
[ImportMany(typeof(BaseWeatherProvider))]
|
||||
public IEnumerable<BaseWeatherProvider> WeatherProviders { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the list of currently registered metadata prvoiders
|
||||
/// </summary>
|
||||
[ImportMany(typeof(BaseMetadataProvider))]
|
||||
private IEnumerable<BaseMetadataProvider> MetadataProvidersEnumerable { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Once MEF has loaded the resolvers, sort them by priority and store them in this array
|
||||
/// Given the sheer number of times they'll be iterated over it'll be faster to loop through an array
|
||||
/// </summary>
|
||||
private BaseMetadataProvider[] MetadataProviders { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the list of currently registered entity resolvers
|
||||
/// </summary>
|
||||
[ImportMany(typeof(IBaseItemResolver))]
|
||||
private IEnumerable<IBaseItemResolver> EntityResolversEnumerable { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Once MEF has loaded the resolvers, sort them by priority and store them in this array
|
||||
/// Given the sheer number of times they'll be iterated over it'll be faster to loop through an array
|
||||
/// </summary>
|
||||
internal IBaseItemResolver[] EntityResolvers { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Creates a kernel based on a Data path, which is akin to our current programdata path
|
||||
/// </summary>
|
||||
public Kernel()
|
||||
: base()
|
||||
{
|
||||
Instance = this;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Performs initializations that only occur once
|
||||
/// </summary>
|
||||
protected override void InitializeInternal(IProgress<TaskProgress> progress)
|
||||
{
|
||||
base.InitializeInternal(progress);
|
||||
|
||||
ItemController = new ItemController();
|
||||
DirectoryWatchers = new DirectoryWatchers();
|
||||
|
||||
|
||||
ExtractFFMpeg();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Performs initializations that can be reloaded at anytime
|
||||
/// </summary>
|
||||
protected override async Task ReloadInternal(IProgress<TaskProgress> progress)
|
||||
{
|
||||
await base.ReloadInternal(progress).ConfigureAwait(false);
|
||||
|
||||
ReportProgress(progress, "Loading Users");
|
||||
ReloadUsers();
|
||||
|
||||
ReportProgress(progress, "Loading Media Library");
|
||||
|
||||
await ReloadRoot(allowInternetProviders: false).ConfigureAwait(false);
|
||||
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Completely disposes the Kernel
|
||||
/// </summary>
|
||||
public override void Dispose()
|
||||
{
|
||||
base.Dispose();
|
||||
|
||||
DirectoryWatchers.Stop();
|
||||
|
||||
}
|
||||
|
||||
protected override void OnComposablePartsLoaded()
|
||||
{
|
||||
// The base class will start up all the plugins
|
||||
base.OnComposablePartsLoaded();
|
||||
|
||||
// Sort the resolvers by priority
|
||||
EntityResolvers = EntityResolversEnumerable.OrderBy(e => e.Priority).ToArray();
|
||||
|
||||
// Sort the providers by priority
|
||||
MetadataProviders = MetadataProvidersEnumerable.OrderBy(e => e.Priority).ToArray();
|
||||
}
|
||||
|
||||
public BaseItem ResolveItem(ItemResolveEventArgs args)
|
||||
{
|
||||
// Try first priority resolvers
|
||||
for (int i = 0; i < EntityResolvers.Length; i++)
|
||||
{
|
||||
var item = EntityResolvers[i].ResolvePath(args);
|
||||
|
||||
if (item != null)
|
||||
{
|
||||
item.ResolveArgs = args;
|
||||
return item;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
private void ReloadUsers()
|
||||
{
|
||||
Users = GetAllUsers();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Reloads the root media folder
|
||||
/// </summary>
|
||||
public async Task ReloadRoot(bool allowInternetProviders = true)
|
||||
{
|
||||
if (!Directory.Exists(MediaRootFolderPath))
|
||||
{
|
||||
Directory.CreateDirectory(MediaRootFolderPath);
|
||||
}
|
||||
|
||||
DirectoryWatchers.Stop();
|
||||
|
||||
RootFolder = await ItemController.GetItem(MediaRootFolderPath, allowInternetProviders: allowInternetProviders).ConfigureAwait(false) as Folder;
|
||||
RootFolder.ChildrenChanged += RootFolder_ChildrenChanged;
|
||||
|
||||
DirectoryWatchers.Start();
|
||||
}
|
||||
|
||||
void RootFolder_ChildrenChanged(object sender, ChildrenChangedEventArgs e)
|
||||
{
|
||||
Logger.LogDebugInfo("Root Folder Children Changed. Added: " + e.ItemsAdded.Count + " Removed: " + e.ItemsRemoved.Count());
|
||||
//re-start the directory watchers
|
||||
DirectoryWatchers.Stop();
|
||||
DirectoryWatchers.Start();
|
||||
//Task.Delay(30000); //let's wait and see if more data gets filled in...
|
||||
var allChildren = RootFolder.RecursiveChildren;
|
||||
Logger.LogDebugInfo(string.Format("Loading complete. Movies: {0} Episodes: {1} Folders: {2}", allChildren.OfType<Entities.Movies.Movie>().Count(), allChildren.OfType<Entities.TV.Episode>().Count(), allChildren.Where(i => i is Folder && !(i is Series || i is Season)).Count()));
|
||||
//foreach (var child in allChildren)
|
||||
//{
|
||||
// Logger.LogDebugInfo("(" + child.GetType().Name + ") " + child.Name + " (" + child.Path + ")");
|
||||
//}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the default user to use when EnableUserProfiles is false
|
||||
/// </summary>
|
||||
public User GetDefaultUser()
|
||||
{
|
||||
User user = Users.FirstOrDefault();
|
||||
|
||||
return user;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Persists a User
|
||||
/// </summary>
|
||||
public void SaveUser(User user)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Authenticates a User and returns a result indicating whether or not it succeeded
|
||||
/// </summary>
|
||||
public AuthenticationResult AuthenticateUser(User user, string password)
|
||||
{
|
||||
var result = new AuthenticationResult();
|
||||
|
||||
// When EnableUserProfiles is false, only the default User can login
|
||||
if (!Configuration.EnableUserProfiles)
|
||||
{
|
||||
result.Success = user.Id == GetDefaultUser().Id;
|
||||
}
|
||||
else if (string.IsNullOrEmpty(user.Password))
|
||||
{
|
||||
result.Success = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
password = password ?? string.Empty;
|
||||
result.Success = password.GetMD5().ToString().Equals(user.Password);
|
||||
}
|
||||
|
||||
// Update LastActivityDate and LastLoginDate, then save
|
||||
if (result.Success)
|
||||
{
|
||||
user.LastActivityDate = user.LastLoginDate = DateTime.UtcNow;
|
||||
SaveUser(user);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Finds a library item by Id
|
||||
/// </summary>
|
||||
public BaseItem GetItemById(Guid id)
|
||||
{
|
||||
if (id == Guid.Empty)
|
||||
{
|
||||
return RootFolder;
|
||||
}
|
||||
|
||||
return RootFolder.FindItemById(id);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets all users within the system
|
||||
/// </summary>
|
||||
private IEnumerable<User> GetAllUsers()
|
||||
{
|
||||
var list = new List<User>();
|
||||
|
||||
// Return a dummy user for now since all calls to get items requre a userId
|
||||
var user = new User { };
|
||||
|
||||
user.Name = "Default User";
|
||||
user.Id = Guid.Parse("5d1cf7fce25943b790d140095457a42b");
|
||||
user.PrimaryImagePath = "D:\\Video\\TV\\Archer (2009)\\backdrop.jpg";
|
||||
list.Add(user);
|
||||
|
||||
user = new User { };
|
||||
user.Name = "Abobader";
|
||||
user.Id = Guid.NewGuid();
|
||||
user.LastLoginDate = DateTime.UtcNow.AddDays(-1);
|
||||
user.LastActivityDate = DateTime.UtcNow.AddHours(-3);
|
||||
user.Password = ("1234").GetMD5().ToString();
|
||||
list.Add(user);
|
||||
|
||||
user = new User { };
|
||||
user.Name = "Scottisafool";
|
||||
user.Id = Guid.NewGuid();
|
||||
list.Add(user);
|
||||
|
||||
user = new User { };
|
||||
user.Name = "Redshirt";
|
||||
user.Id = Guid.NewGuid();
|
||||
list.Add(user);
|
||||
|
||||
/*user = new User();
|
||||
user.Name = "Test User 4";
|
||||
user.Id = Guid.NewGuid();
|
||||
list.Add(user);
|
||||
|
||||
user = new User();
|
||||
user.Name = "Test User 5";
|
||||
user.Id = Guid.NewGuid();
|
||||
list.Add(user);
|
||||
|
||||
user = new User();
|
||||
user.Name = "Test User 6";
|
||||
user.Id = Guid.NewGuid();
|
||||
list.Add(user);*/
|
||||
|
||||
return list;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Runs all metadata providers for an entity
|
||||
/// </summary>
|
||||
internal async Task ExecuteMetadataProviders(BaseEntity item, bool allowInternetProviders = true)
|
||||
{
|
||||
// Run them sequentially in order of priority
|
||||
for (int i = 0; i < MetadataProviders.Length; i++)
|
||||
{
|
||||
var provider = MetadataProviders[i];
|
||||
|
||||
// Skip if internet providers are currently disabled
|
||||
if (provider.RequiresInternet && (!Configuration.EnableInternetProviders || !allowInternetProviders))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
// Skip if the provider doesn't support the current item
|
||||
if (!provider.Supports(item))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
await provider.FetchIfNeededAsync(item).ConfigureAwait(false);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Logger.LogException(ex);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void ExtractFFMpeg()
|
||||
{
|
||||
ExtractFFMpeg(ApplicationPaths.FFMpegPath);
|
||||
ExtractFFMpeg(ApplicationPaths.FFProbePath);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Run these during Init.
|
||||
/// Can't run do this on-demand because there will be multiple workers accessing them at once and we'd have to lock them
|
||||
/// </summary>
|
||||
private void ExtractFFMpeg(string exe)
|
||||
{
|
||||
if (File.Exists(exe))
|
||||
{
|
||||
File.Delete(exe);
|
||||
}
|
||||
|
||||
// Extract exe
|
||||
using (Stream stream = Assembly.GetExecutingAssembly().GetManifestResourceStream("MediaBrowser.Controller.FFMpeg." + Path.GetFileName(exe)))
|
||||
{
|
||||
using (var fileStream = new FileStream(exe, FileMode.Create))
|
||||
{
|
||||
stream.CopyTo(fileStream);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
using MediaBrowser.Common.Kernel;
|
||||
using MediaBrowser.Common.Plugins;
|
||||
using MediaBrowser.Controller.Drawing;
|
||||
using MediaBrowser.Controller.Entities;
|
||||
using MediaBrowser.Controller.IO;
|
||||
using MediaBrowser.Controller.Library;
|
||||
using MediaBrowser.Controller.MediaInfo;
|
||||
using MediaBrowser.Controller.Persistence;
|
||||
using MediaBrowser.Controller.Persistence.SQLite;
|
||||
using MediaBrowser.Controller.Playback;
|
||||
using MediaBrowser.Controller.Plugins;
|
||||
using MediaBrowser.Controller.Providers;
|
||||
using MediaBrowser.Controller.Resolvers;
|
||||
using MediaBrowser.Controller.ScheduledTasks;
|
||||
using MediaBrowser.Controller.Updates;
|
||||
using MediaBrowser.Controller.Weather;
|
||||
using MediaBrowser.Model.Configuration;
|
||||
using MediaBrowser.Model.System;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel.Composition;
|
||||
using System.Diagnostics;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace MediaBrowser.Controller
|
||||
{
|
||||
/// <summary>
|
||||
/// Class Kernel
|
||||
/// </summary>
|
||||
public class Kernel : BaseKernel<ServerConfiguration, ServerApplicationPaths>
|
||||
{
|
||||
/// <summary>
|
||||
/// The MB admin URL
|
||||
/// </summary>
|
||||
public const string MBAdminUrl = "http://mb3admin.com/admin/";
|
||||
|
||||
/// <summary>
|
||||
/// Gets the instance.
|
||||
/// </summary>
|
||||
/// <value>The instance.</value>
|
||||
public static Kernel Instance { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the library manager.
|
||||
/// </summary>
|
||||
/// <value>The library manager.</value>
|
||||
public LibraryManager LibraryManager { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the image manager.
|
||||
/// </summary>
|
||||
/// <value>The image manager.</value>
|
||||
public ImageManager ImageManager { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the user manager.
|
||||
/// </summary>
|
||||
/// <value>The user manager.</value>
|
||||
public UserManager UserManager { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the FFMPEG controller.
|
||||
/// </summary>
|
||||
/// <value>The FFMPEG controller.</value>
|
||||
public FFMpegManager FFMpegManager { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the installation manager.
|
||||
/// </summary>
|
||||
/// <value>The installation manager.</value>
|
||||
public InstallationManager InstallationManager { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the file system manager.
|
||||
/// </summary>
|
||||
/// <value>The file system manager.</value>
|
||||
public FileSystemManager FileSystemManager { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the provider manager.
|
||||
/// </summary>
|
||||
/// <value>The provider manager.</value>
|
||||
public ProviderManager ProviderManager { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the user data manager.
|
||||
/// </summary>
|
||||
/// <value>The user data manager.</value>
|
||||
public UserDataManager UserDataManager { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the plug-in security manager.
|
||||
/// </summary>
|
||||
/// <value>The plug-in security manager.</value>
|
||||
public PluginSecurityManager PluginSecurityManager { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// The _users
|
||||
/// </summary>
|
||||
private IEnumerable<User> _users;
|
||||
/// <summary>
|
||||
/// The _user lock
|
||||
/// </summary>
|
||||
private object _usersSyncLock = new object();
|
||||
/// <summary>
|
||||
/// The _users initialized
|
||||
/// </summary>
|
||||
private bool _usersInitialized;
|
||||
/// <summary>
|
||||
/// Gets the users.
|
||||
/// </summary>
|
||||
/// <value>The users.</value>
|
||||
public IEnumerable<User> Users
|
||||
{
|
||||
get
|
||||
{
|
||||
// Call ToList to exhaust the stream because we'll be iterating over this multiple times
|
||||
LazyInitializer.EnsureInitialized(ref _users, ref _usersInitialized, ref _usersSyncLock, UserManager.LoadUsers);
|
||||
return _users;
|
||||
}
|
||||
internal set
|
||||
{
|
||||
_users = value;
|
||||
|
||||
if (value == null)
|
||||
{
|
||||
_usersInitialized = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The _root folder
|
||||
/// </summary>
|
||||
private AggregateFolder _rootFolder;
|
||||
/// <summary>
|
||||
/// The _root folder sync lock
|
||||
/// </summary>
|
||||
private object _rootFolderSyncLock = new object();
|
||||
/// <summary>
|
||||
/// The _root folder initialized
|
||||
/// </summary>
|
||||
private bool _rootFolderInitialized;
|
||||
/// <summary>
|
||||
/// Gets the root folder.
|
||||
/// </summary>
|
||||
/// <value>The root folder.</value>
|
||||
public AggregateFolder RootFolder
|
||||
{
|
||||
get
|
||||
{
|
||||
LazyInitializer.EnsureInitialized(ref _rootFolder, ref _rootFolderInitialized, ref _rootFolderSyncLock, LibraryManager.CreateRootFolder);
|
||||
return _rootFolder;
|
||||
}
|
||||
private set
|
||||
{
|
||||
_rootFolder = value;
|
||||
|
||||
if (value == null)
|
||||
{
|
||||
_rootFolderInitialized = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the kernel context.
|
||||
/// </summary>
|
||||
/// <value>The kernel context.</value>
|
||||
public override KernelContext KernelContext
|
||||
{
|
||||
get { return KernelContext.Server; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the list of plugin configuration pages
|
||||
/// </summary>
|
||||
/// <value>The configuration pages.</value>
|
||||
[ImportMany(typeof(BaseConfigurationPage))]
|
||||
public IEnumerable<BaseConfigurationPage> PluginConfigurationPages { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the intro providers.
|
||||
/// </summary>
|
||||
/// <value>The intro providers.</value>
|
||||
[ImportMany(typeof(BaseIntroProvider))]
|
||||
public IEnumerable<BaseIntroProvider> IntroProviders { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the list of currently registered weather prvoiders
|
||||
/// </summary>
|
||||
/// <value>The weather providers.</value>
|
||||
[ImportMany(typeof(BaseWeatherProvider))]
|
||||
public IEnumerable<BaseWeatherProvider> WeatherProviders { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the list of currently registered metadata prvoiders
|
||||
/// </summary>
|
||||
/// <value>The metadata providers enumerable.</value>
|
||||
[ImportMany(typeof(BaseMetadataProvider))]
|
||||
public BaseMetadataProvider[] MetadataProviders { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the list of currently registered image processors
|
||||
/// Image processors are specialized metadata providers that run after the normal ones
|
||||
/// </summary>
|
||||
/// <value>The image enhancers.</value>
|
||||
[ImportMany(typeof(BaseImageEnhancer))]
|
||||
public BaseImageEnhancer[] ImageEnhancers { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the list of currently registered entity resolvers
|
||||
/// </summary>
|
||||
/// <value>The entity resolvers enumerable.</value>
|
||||
[ImportMany(typeof(IBaseItemResolver))]
|
||||
internal IBaseItemResolver[] EntityResolvers { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the list of BasePluginFolders added by plugins
|
||||
/// </summary>
|
||||
/// <value>The plugin folders.</value>
|
||||
[ImportMany(typeof(BasePluginFolder))]
|
||||
internal IEnumerable<BasePluginFolder> PluginFolders { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the list of available user repositories
|
||||
/// </summary>
|
||||
/// <value>The user repositories.</value>
|
||||
[ImportMany(typeof(IUserRepository))]
|
||||
private IEnumerable<IUserRepository> UserRepositories { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the active user repository
|
||||
/// </summary>
|
||||
/// <value>The user repository.</value>
|
||||
public IUserRepository UserRepository { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the active user repository
|
||||
/// </summary>
|
||||
/// <value>The display preferences repository.</value>
|
||||
public IDisplayPreferencesRepository DisplayPreferencesRepository { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the list of available item repositories
|
||||
/// </summary>
|
||||
/// <value>The item repositories.</value>
|
||||
[ImportMany(typeof(IItemRepository))]
|
||||
private IEnumerable<IItemRepository> ItemRepositories { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the active item repository
|
||||
/// </summary>
|
||||
/// <value>The item repository.</value>
|
||||
public IItemRepository ItemRepository { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the list of available item repositories
|
||||
/// </summary>
|
||||
/// <value>The user data repositories.</value>
|
||||
[ImportMany(typeof(IUserDataRepository))]
|
||||
private IEnumerable<IUserDataRepository> UserDataRepositories { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the list of available DisplayPreferencesRepositories
|
||||
/// </summary>
|
||||
/// <value>The display preferences repositories.</value>
|
||||
[ImportMany(typeof(IDisplayPreferencesRepository))]
|
||||
private IEnumerable<IDisplayPreferencesRepository> DisplayPreferencesRepositories { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the list of entity resolution ignore rules
|
||||
/// </summary>
|
||||
/// <value>The entity resolution ignore rules.</value>
|
||||
[ImportMany(typeof(BaseResolutionIgnoreRule))]
|
||||
internal IEnumerable<BaseResolutionIgnoreRule> EntityResolutionIgnoreRules { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the active user data repository
|
||||
/// </summary>
|
||||
/// <value>The user data repository.</value>
|
||||
public IUserDataRepository UserDataRepository { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Limits simultaneous access to various resources
|
||||
/// </summary>
|
||||
/// <value>The resource pools.</value>
|
||||
public ResourcePool ResourcePools { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the UDP server port number.
|
||||
/// </summary>
|
||||
/// <value>The UDP server port number.</value>
|
||||
public override int UdpServerPortNumber
|
||||
{
|
||||
get { return 7359; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates a kernel based on a Data path, which is akin to our current programdata path
|
||||
/// </summary>
|
||||
public Kernel()
|
||||
: base()
|
||||
{
|
||||
Instance = this;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Performs initializations that can be reloaded at anytime
|
||||
/// </summary>
|
||||
/// <returns>Task.</returns>
|
||||
protected override async Task ReloadInternal()
|
||||
{
|
||||
Logger.Info("Extracting tools");
|
||||
|
||||
// Reset these so that they can be lazy loaded again
|
||||
Users = null;
|
||||
RootFolder = null;
|
||||
|
||||
ReloadResourcePools();
|
||||
InstallationManager = new InstallationManager(this);
|
||||
LibraryManager = new LibraryManager(this);
|
||||
UserManager = new UserManager(this);
|
||||
FFMpegManager = new FFMpegManager(this);
|
||||
ImageManager = new ImageManager(this);
|
||||
ProviderManager = new ProviderManager(this);
|
||||
UserDataManager = new UserDataManager(this);
|
||||
PluginSecurityManager = new PluginSecurityManager(this);
|
||||
|
||||
await base.ReloadInternal().ConfigureAwait(false);
|
||||
|
||||
ReloadFileSystemManager();
|
||||
|
||||
await UserManager.RefreshUsersMetadata(CancellationToken.None).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
/// <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 override void Dispose(bool dispose)
|
||||
{
|
||||
if (dispose)
|
||||
{
|
||||
DisposeResourcePools();
|
||||
|
||||
DisposeFileSystemManager();
|
||||
}
|
||||
|
||||
base.Dispose(dispose);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Disposes the resource pools.
|
||||
/// </summary>
|
||||
private void DisposeResourcePools()
|
||||
{
|
||||
if (ResourcePools != null)
|
||||
{
|
||||
ResourcePools.Dispose();
|
||||
ResourcePools = null;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Reloads the resource pools.
|
||||
/// </summary>
|
||||
private void ReloadResourcePools()
|
||||
{
|
||||
DisposeResourcePools();
|
||||
ResourcePools = new ResourcePool();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Called when [composable parts loaded].
|
||||
/// </summary>
|
||||
/// <returns>Task.</returns>
|
||||
protected override async Task OnComposablePartsLoaded()
|
||||
{
|
||||
// The base class will start up all the plugins
|
||||
await base.OnComposablePartsLoaded().ConfigureAwait(false);
|
||||
|
||||
// Get the current item repository
|
||||
ItemRepository = GetRepository(ItemRepositories, Configuration.ItemRepository, SQLiteItemRepository.RepositoryName);
|
||||
var itemRepoTask = ItemRepository.Initialize();
|
||||
|
||||
// Get the current user repository
|
||||
UserRepository = GetRepository(UserRepositories, Configuration.UserRepository, SQLiteUserRepository.RepositoryName);
|
||||
var userRepoTask = UserRepository.Initialize();
|
||||
|
||||
// Get the current item repository
|
||||
UserDataRepository = GetRepository(UserDataRepositories, Configuration.UserDataRepository, SQLiteUserDataRepository.RepositoryName);
|
||||
var userDataRepoTask = UserDataRepository.Initialize();
|
||||
|
||||
// Get the current display preferences repository
|
||||
DisplayPreferencesRepository = GetRepository(DisplayPreferencesRepositories, Configuration.DisplayPreferencesRepository, SQLiteDisplayPreferencesRepository.RepositoryName);
|
||||
var displayPreferencesRepoTask = DisplayPreferencesRepository.Initialize();
|
||||
|
||||
// Sort the resolvers by priority
|
||||
EntityResolvers = EntityResolvers.OrderBy(e => e.Priority).ToArray();
|
||||
|
||||
// Sort the providers by priority
|
||||
MetadataProviders = MetadataProviders.OrderBy(e => e.Priority).ToArray();
|
||||
|
||||
// Sort the image processors by priority
|
||||
ImageEnhancers = ImageEnhancers.OrderBy(e => e.Priority).ToArray();
|
||||
|
||||
await Task.WhenAll(itemRepoTask, userRepoTask, userDataRepoTask, displayPreferencesRepoTask).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
protected override IEnumerable<Assembly> GetComposablePartAssemblies()
|
||||
{
|
||||
var runningDirectory = Path.GetDirectoryName(Process.GetCurrentProcess().MainModule.FileName);
|
||||
|
||||
return base.GetComposablePartAssemblies().Concat(new[] {
|
||||
|
||||
Assembly.Load(File.ReadAllBytes(Path.Combine(runningDirectory, "MediaBrowser.Api.dll"))),
|
||||
Assembly.Load(File.ReadAllBytes(Path.Combine(runningDirectory, "MediaBrowser.ApiInteraction.Javascript.dll"))),
|
||||
Assembly.Load(File.ReadAllBytes(Path.Combine(runningDirectory, "MediaBrowser.WebDashboard.dll")))
|
||||
});
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets a repository by name from a list, and returns the default if not found
|
||||
/// </summary>
|
||||
/// <typeparam name="T"></typeparam>
|
||||
/// <param name="repositories">The repositories.</param>
|
||||
/// <param name="name">The name.</param>
|
||||
/// <param name="defaultName">The default name.</param>
|
||||
/// <returns>``0.</returns>
|
||||
private T GetRepository<T>(IEnumerable<T> repositories, string name, string defaultName)
|
||||
where T : class, IRepository
|
||||
{
|
||||
var enumerable = repositories as T[] ?? repositories.ToArray();
|
||||
|
||||
return enumerable.FirstOrDefault(r => r.Name.Equals(name ?? defaultName, StringComparison.OrdinalIgnoreCase)) ??
|
||||
enumerable.First(r => r.Name.Equals(defaultName, StringComparison.OrdinalIgnoreCase));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Disposes the file system manager.
|
||||
/// </summary>
|
||||
private void DisposeFileSystemManager()
|
||||
{
|
||||
if (FileSystemManager != null)
|
||||
{
|
||||
FileSystemManager.Dispose();
|
||||
FileSystemManager = null;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Reloads the file system manager.
|
||||
/// </summary>
|
||||
private void ReloadFileSystemManager()
|
||||
{
|
||||
DisposeFileSystemManager();
|
||||
|
||||
FileSystemManager = new FileSystemManager(this);
|
||||
FileSystemManager.StartWatchers();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets a User by Id
|
||||
/// </summary>
|
||||
/// <param name="id">The id.</param>
|
||||
/// <returns>User.</returns>
|
||||
/// <exception cref="System.ArgumentNullException"></exception>
|
||||
public User GetUserById(Guid id)
|
||||
{
|
||||
if (id == Guid.Empty)
|
||||
{
|
||||
throw new ArgumentNullException();
|
||||
}
|
||||
|
||||
return Users.FirstOrDefault(u => u.Id == id);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Finds a library item by Id and UserId.
|
||||
/// </summary>
|
||||
/// <param name="id">The id.</param>
|
||||
/// <param name="userId">The user id.</param>
|
||||
/// <returns>BaseItem.</returns>
|
||||
/// <exception cref="System.ArgumentNullException">id</exception>
|
||||
public BaseItem GetItemById(Guid id, Guid userId)
|
||||
{
|
||||
if (id == Guid.Empty)
|
||||
{
|
||||
throw new ArgumentNullException("id");
|
||||
}
|
||||
|
||||
if (userId == Guid.Empty)
|
||||
{
|
||||
throw new ArgumentNullException("userId");
|
||||
}
|
||||
|
||||
var user = GetUserById(userId);
|
||||
var userRoot = user.RootFolder;
|
||||
|
||||
return userRoot.FindItemById(id, user);
|
||||
}
|
||||
|
||||
/// <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");
|
||||
}
|
||||
|
||||
return RootFolder.FindItemById(id, null);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Completely overwrites the current configuration with a new copy
|
||||
/// </summary>
|
||||
/// <param name="config">The config.</param>
|
||||
public void UpdateConfiguration(ServerConfiguration config)
|
||||
{
|
||||
var oldConfiguration = Configuration;
|
||||
|
||||
var reloadLogger = config.ShowLogWindow != oldConfiguration.ShowLogWindow;
|
||||
|
||||
// Figure out whether or not we should refresh people after the update is finished
|
||||
var refreshPeopleAfterUpdate = !oldConfiguration.EnableInternetProviders && config.EnableInternetProviders;
|
||||
|
||||
// This is true if internet providers has just been turned on, or if People have just been removed from InternetProviderExcludeTypes
|
||||
if (!refreshPeopleAfterUpdate)
|
||||
{
|
||||
var oldConfigurationFetchesPeopleImages = oldConfiguration.InternetProviderExcludeTypes == null || !oldConfiguration.InternetProviderExcludeTypes.Contains(typeof(Person).Name, StringComparer.OrdinalIgnoreCase);
|
||||
var newConfigurationFetchesPeopleImages = config.InternetProviderExcludeTypes == null || !config.InternetProviderExcludeTypes.Contains(typeof(Person).Name, StringComparer.OrdinalIgnoreCase);
|
||||
|
||||
refreshPeopleAfterUpdate = newConfigurationFetchesPeopleImages && !oldConfigurationFetchesPeopleImages;
|
||||
}
|
||||
|
||||
Configuration = config;
|
||||
SaveConfiguration();
|
||||
|
||||
if (reloadLogger)
|
||||
{
|
||||
ReloadLogger();
|
||||
}
|
||||
|
||||
TcpManager.OnApplicationConfigurationChanged(oldConfiguration, config);
|
||||
|
||||
// Validate currently executing providers, in the background
|
||||
Task.Run(() =>
|
||||
{
|
||||
ProviderManager.ValidateCurrentlyRunningProviders();
|
||||
|
||||
// Any number of configuration settings could change the way the library is refreshed, so do that now
|
||||
TaskManager.CancelIfRunningAndQueue<RefreshMediaLibraryTask>();
|
||||
|
||||
if (refreshPeopleAfterUpdate)
|
||||
{
|
||||
TaskManager.CancelIfRunningAndQueue<PeopleValidationTask>();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Removes the plugin.
|
||||
/// </summary>
|
||||
/// <param name="plugin">The plugin.</param>
|
||||
internal void RemovePlugin(IPlugin plugin)
|
||||
{
|
||||
var list = Plugins.ToList();
|
||||
list.Remove(plugin);
|
||||
Plugins = list;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the system info.
|
||||
/// </summary>
|
||||
/// <returns>SystemInfo.</returns>
|
||||
public override SystemInfo GetSystemInfo()
|
||||
{
|
||||
var info = base.GetSystemInfo();
|
||||
|
||||
if (InstallationManager != null)
|
||||
{
|
||||
info.InProgressInstallations = InstallationManager.CurrentInstallations.Select(i => i.Item1).ToArray();
|
||||
info.CompletedInstallations = InstallationManager.CompletedInstallations.ToArray();
|
||||
}
|
||||
|
||||
return info;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user