From 868a7ce9c8b50bd64c8b5ae33fec77abfd25ef7c Mon Sep 17 00:00:00 2001 From: LukePulverenti Date: Thu, 21 Feb 2013 23:23:06 -0500 Subject: [PATCH] isolated clickonce dependancies --- MediaBrowser.Api/EnvironmentService.cs | 1 + MediaBrowser.Api/MediaBrowser.Api.csproj | 9 +-- MediaBrowser.Api/PackageService.cs | 13 ++-- .../ScheduledTasks/ScheduledTaskService.cs | 2 +- .../ScheduledTasksWebSocketListener.cs | 2 +- .../WebSocket}/LogFileWebSocketListener.cs | 2 +- .../WebSocket}/SystemInfoWebSocketListener.cs | 7 +- .../ApplicationUpdateCheck.cs | 32 ++++++--- .../ApplicationUpdater.cs | 11 ++-- .../ClickOnceHelper.cs | 42 +++++++++++- .../MediaBrowser.ClickOnce.csproj | 62 ++++++++++++++++++ .../Properties/AssemblyInfo.cs | 36 ++++++++++ .../Extensions/BaseExtensions.cs | 19 ------ MediaBrowser.Common/Kernel/BaseKernel.cs | 19 +++--- .../Kernel/IApplicationHost.cs | 30 ++++++++- MediaBrowser.Common/Kernel/TcpManager.cs | 11 +++- .../MediaBrowser.Common.csproj | 17 +---- MediaBrowser.Common/Net/HttpServer.cs | 15 ++++- MediaBrowser.Common/Net/StaticResult.cs | 14 ---- MediaBrowser.Common/Resources/Images/Icon.ico | Bin 149571 -> 0 bytes .../ScheduledTasks/BaseScheduledTask.cs | 8 +-- .../ScheduledTasks/IScheduledTask.cs | 2 +- .../ScheduledTasks/ScheduledTaskHelpers.cs | 2 +- .../Tasks/DeleteCacheFileTask.cs | 8 +-- .../ScheduledTasks/Tasks/DeleteLogFileTask.cs | 6 +- .../ScheduledTasks/Tasks/ReloadLoggerTask.cs | 4 +- .../ScheduledTasks/Tasks/SystemUpdateTask.cs | 42 +++++++----- .../Entities/CollectionFolder.cs | 2 +- MediaBrowser.Controller/Entities/Folder.cs | 18 ++--- MediaBrowser.Controller/Entities/User.cs | 6 +- .../IO}/NetworkShares.cs | 2 +- .../Library/LibraryManager.cs | 14 ++-- .../MediaBrowser.Controller.csproj | 2 +- .../ScheduledTasks/ChapterImagesTask.cs | 4 +- .../ScheduledTasks/ImageCleanupTask.cs | 4 +- .../ScheduledTasks/PeopleValidationTask.cs | 2 +- .../ScheduledTasks/PluginUpdateTask.cs | 10 +-- .../ScheduledTasks/RefreshMediaLibraryTask.cs | 4 +- MediaBrowser.Model/MediaBrowser.Model.csproj | 2 +- MediaBrowser.Model/Tasks/TaskInfo.cs | 2 +- MediaBrowser.Model/Tasks/TaskProgress.cs | 22 ------- .../Updates/CheckForUpdateResult.cs | 22 +++++++ .../CurrentTrailerDownloadTask.cs | 8 +-- .../MediaBrowser.Server.Uninstall.csproj | 6 +- MediaBrowser.Server.Uninstall/Program.cs | 2 +- MediaBrowser.ServerApplication/App.xaml.cs | 56 ++++++++++------ .../LibraryExplorer.xaml.cs | 2 +- .../MediaBrowser.ServerApplication.csproj | 5 +- .../MediaBrowser.UI.Uninstall.csproj | 6 +- MediaBrowser.UI.Uninstall/Program.cs | 2 +- MediaBrowser.UI.sln | 12 ++++ MediaBrowser.UI/App.xaml.cs | 62 +++++++++++------- MediaBrowser.UI/Extensions/Extensions.cs | 26 ++++++++ MediaBrowser.UI/MainWindow.xaml.cs | 1 + MediaBrowser.UI/MediaBrowser.UI.csproj | 6 +- .../Html/scripts/DashboardPage.js | 4 +- .../Html/scripts/ScheduledTasksPage.js | 3 +- MediaBrowser.sln | 16 +++++ 58 files changed, 505 insertions(+), 244 deletions(-) rename {MediaBrowser.Common/Api => MediaBrowser.Api}/ScheduledTasks/ScheduledTaskService.cs (99%) rename {MediaBrowser.Common/Api => MediaBrowser.Api}/ScheduledTasks/ScheduledTasksWebSocketListener.cs (96%) rename {MediaBrowser.Common/Api/Logging => MediaBrowser.Api/WebSocket}/LogFileWebSocketListener.cs (99%) rename {MediaBrowser.Common/Api => MediaBrowser.Api/WebSocket}/SystemInfoWebSocketListener.cs (86%) rename {MediaBrowser.Common/Updates => MediaBrowser.ClickOnce}/ApplicationUpdateCheck.cs (74%) rename {MediaBrowser.Common/Updates => MediaBrowser.ClickOnce}/ApplicationUpdater.cs (91%) rename {MediaBrowser.Common/Updates => MediaBrowser.ClickOnce}/ClickOnceHelper.cs (82%) create mode 100644 MediaBrowser.ClickOnce/MediaBrowser.ClickOnce.csproj create mode 100644 MediaBrowser.ClickOnce/Properties/AssemblyInfo.cs delete mode 100644 MediaBrowser.Common/Net/StaticResult.cs delete mode 100644 MediaBrowser.Common/Resources/Images/Icon.ico rename {MediaBrowser.Common/Net => MediaBrowser.Controller/IO}/NetworkShares.cs (99%) delete mode 100644 MediaBrowser.Model/Tasks/TaskProgress.cs create mode 100644 MediaBrowser.Model/Updates/CheckForUpdateResult.cs create mode 100644 MediaBrowser.UI/Extensions/Extensions.cs diff --git a/MediaBrowser.Api/EnvironmentService.cs b/MediaBrowser.Api/EnvironmentService.cs index e552c7f1de..db768d0e84 100644 --- a/MediaBrowser.Api/EnvironmentService.cs +++ b/MediaBrowser.Api/EnvironmentService.cs @@ -1,5 +1,6 @@ using MediaBrowser.Common.IO; using MediaBrowser.Common.Net; +using MediaBrowser.Controller.IO; using MediaBrowser.Model.IO; using ServiceStack.ServiceHost; using System; diff --git a/MediaBrowser.Api/MediaBrowser.Api.csproj b/MediaBrowser.Api/MediaBrowser.Api.csproj index 546cf44928..220101de54 100644 --- a/MediaBrowser.Api/MediaBrowser.Api.csproj +++ b/MediaBrowser.Api/MediaBrowser.Api.csproj @@ -66,14 +66,11 @@ - - - - + @@ -87,6 +84,8 @@ + + @@ -108,6 +107,8 @@ + + diff --git a/MediaBrowser.Api/PackageService.cs b/MediaBrowser.Api/PackageService.cs index 64c5d6cbc7..924c339371 100644 --- a/MediaBrowser.Api/PackageService.cs +++ b/MediaBrowser.Api/PackageService.cs @@ -1,8 +1,7 @@ using MediaBrowser.Common.Extensions; +using MediaBrowser.Common.Kernel; using MediaBrowser.Common.Net; -using MediaBrowser.Common.Updates; using MediaBrowser.Controller; -using MediaBrowser.Model.Tasks; using MediaBrowser.Model.Updates; using ServiceStack.ServiceHost; using System; @@ -97,6 +96,12 @@ namespace MediaBrowser.Api [Export(typeof(IRestfulService))] public class PackageService : BaseRestService { + /// + /// Gets or sets the application host. + /// + /// The application host. + public IApplicationHost ApplicationHost { get; set; } + /// /// Gets the specified request. /// @@ -116,9 +121,9 @@ namespace MediaBrowser.Api else if (request.PackageType == PackageType.System || request.PackageType == PackageType.All) { - var updateCheckResult = new ApplicationUpdateCheck().CheckForApplicationUpdate(CancellationToken.None, new Progress { }).Result; + var updateCheckResult = ApplicationHost.CheckForApplicationUpdate(CancellationToken.None, new Progress { }).Result; - if (updateCheckResult.UpdateAvailable) + if (updateCheckResult.IsUpdateAvailable) { result.Add(new PackageVersionInfo { diff --git a/MediaBrowser.Common/Api/ScheduledTasks/ScheduledTaskService.cs b/MediaBrowser.Api/ScheduledTasks/ScheduledTaskService.cs similarity index 99% rename from MediaBrowser.Common/Api/ScheduledTasks/ScheduledTaskService.cs rename to MediaBrowser.Api/ScheduledTasks/ScheduledTaskService.cs index 1df24dcd27..bd12454a00 100644 --- a/MediaBrowser.Common/Api/ScheduledTasks/ScheduledTaskService.cs +++ b/MediaBrowser.Api/ScheduledTasks/ScheduledTaskService.cs @@ -11,7 +11,7 @@ using System.IO; using System.Linq; using ServiceStack.Text.Controller; -namespace MediaBrowser.Common.Api.ScheduledTasks +namespace MediaBrowser.Api.ScheduledTasks { /// /// Class GetScheduledTask diff --git a/MediaBrowser.Common/Api/ScheduledTasks/ScheduledTasksWebSocketListener.cs b/MediaBrowser.Api/ScheduledTasks/ScheduledTasksWebSocketListener.cs similarity index 96% rename from MediaBrowser.Common/Api/ScheduledTasks/ScheduledTasksWebSocketListener.cs rename to MediaBrowser.Api/ScheduledTasks/ScheduledTasksWebSocketListener.cs index 7e4596d9da..7fa47735e5 100644 --- a/MediaBrowser.Common/Api/ScheduledTasks/ScheduledTasksWebSocketListener.cs +++ b/MediaBrowser.Api/ScheduledTasks/ScheduledTasksWebSocketListener.cs @@ -7,7 +7,7 @@ using System.ComponentModel.Composition; using System.Linq; using System.Threading.Tasks; -namespace MediaBrowser.Common.Api.ScheduledTasks +namespace MediaBrowser.Api.ScheduledTasks { /// /// Class ScheduledTasksWebSocketListener diff --git a/MediaBrowser.Common/Api/Logging/LogFileWebSocketListener.cs b/MediaBrowser.Api/WebSocket/LogFileWebSocketListener.cs similarity index 99% rename from MediaBrowser.Common/Api/Logging/LogFileWebSocketListener.cs rename to MediaBrowser.Api/WebSocket/LogFileWebSocketListener.cs index e873facb11..f725b02222 100644 --- a/MediaBrowser.Common/Api/Logging/LogFileWebSocketListener.cs +++ b/MediaBrowser.Api/WebSocket/LogFileWebSocketListener.cs @@ -8,7 +8,7 @@ using System.Linq; using System.Threading.Tasks; using MediaBrowser.Model.Logging; -namespace MediaBrowser.Common.Api.Logging +namespace MediaBrowser.Api.WebSocket { /// /// Class ScheduledTasksWebSocketListener diff --git a/MediaBrowser.Common/Api/SystemInfoWebSocketListener.cs b/MediaBrowser.Api/WebSocket/SystemInfoWebSocketListener.cs similarity index 86% rename from MediaBrowser.Common/Api/SystemInfoWebSocketListener.cs rename to MediaBrowser.Api/WebSocket/SystemInfoWebSocketListener.cs index a216937edc..51d9f2fcda 100644 --- a/MediaBrowser.Common/Api/SystemInfoWebSocketListener.cs +++ b/MediaBrowser.Api/WebSocket/SystemInfoWebSocketListener.cs @@ -1,15 +1,16 @@ using MediaBrowser.Common.Kernel; using MediaBrowser.Model.Logging; +using MediaBrowser.Model.System; using System.ComponentModel.Composition; using System.Threading.Tasks; -namespace MediaBrowser.Common.Api +namespace MediaBrowser.Api.WebSocket { /// /// Class SystemInfoWebSocketListener /// [Export(typeof(IWebSocketListener))] - public class SystemInfoWebSocketListener : BasePeriodicWebSocketListener + public class SystemInfoWebSocketListener : BasePeriodicWebSocketListener { /// /// Gets the name. @@ -36,7 +37,7 @@ namespace MediaBrowser.Common.Api /// /// The state. /// Task{SystemInfo}. - protected override Task GetDataToSend(object state) + protected override Task GetDataToSend(object state) { return Task.FromResult(Kernel.GetSystemInfo()); } diff --git a/MediaBrowser.Common/Updates/ApplicationUpdateCheck.cs b/MediaBrowser.ClickOnce/ApplicationUpdateCheck.cs similarity index 74% rename from MediaBrowser.Common/Updates/ApplicationUpdateCheck.cs rename to MediaBrowser.ClickOnce/ApplicationUpdateCheck.cs index 7501d7321b..72c42f5866 100644 --- a/MediaBrowser.Common/Updates/ApplicationUpdateCheck.cs +++ b/MediaBrowser.ClickOnce/ApplicationUpdateCheck.cs @@ -1,10 +1,10 @@ -using MediaBrowser.Model.Tasks; +using MediaBrowser.Model.Updates; using System; using System.Deployment.Application; using System.Threading; using System.Threading.Tasks; -namespace MediaBrowser.Common.Updates +namespace MediaBrowser.ClickOnce { /// /// Class ApplicationUpdateCheck @@ -14,12 +14,12 @@ namespace MediaBrowser.Common.Updates /// /// The _task completion source /// - private TaskCompletionSource _taskCompletionSource; + private TaskCompletionSource _taskCompletionSource; /// /// The _progress /// - private IProgress _progress; + private IProgress _progress; /// /// Checks for application update. @@ -28,7 +28,7 @@ namespace MediaBrowser.Common.Updates /// The progress. /// Task{CheckForUpdateCompletedEventArgs}. /// Current deployment is not a ClickOnce deployment - public Task CheckForApplicationUpdate(CancellationToken cancellationToken, IProgress progress) + public Task CheckForApplicationUpdate(CancellationToken cancellationToken, IProgress progress) { if (!ApplicationDeployment.IsNetworkDeployed) { @@ -36,8 +36,8 @@ namespace MediaBrowser.Common.Updates } _progress = progress; - - _taskCompletionSource = new TaskCompletionSource(); + + _taskCompletionSource = new TaskCompletionSource(); var deployment = ApplicationDeployment.CurrentDeployment; @@ -53,6 +53,20 @@ namespace MediaBrowser.Common.Updates return _taskCompletionSource.Task; } + /// + /// To the result. + /// + /// The instance containing the event data. + /// CheckForUpdateResult. + private CheckForUpdateResult ToResult(CheckForUpdateCompletedEventArgs args) + { + return new CheckForUpdateResult + { + AvailableVersion = args.AvailableVersion, + IsUpdateAvailable = args.UpdateAvailable + }; + } + /// /// Handles the CheckForUpdateCompleted event of the deployment control. /// @@ -75,7 +89,7 @@ namespace MediaBrowser.Common.Updates } else { - _taskCompletionSource.SetResult(e); + _taskCompletionSource.SetResult(ToResult(e)); } } @@ -86,7 +100,7 @@ namespace MediaBrowser.Common.Updates /// The instance containing the event data. void deployment_CheckForUpdateProgressChanged(object sender, DeploymentProgressChangedEventArgs e) { - _progress.Report(new TaskProgress { PercentComplete = e.ProgressPercentage }); + _progress.Report(e.ProgressPercentage); } } } diff --git a/MediaBrowser.Common/Updates/ApplicationUpdater.cs b/MediaBrowser.ClickOnce/ApplicationUpdater.cs similarity index 91% rename from MediaBrowser.Common/Updates/ApplicationUpdater.cs rename to MediaBrowser.ClickOnce/ApplicationUpdater.cs index d8ae87b375..29af406f1e 100644 --- a/MediaBrowser.Common/Updates/ApplicationUpdater.cs +++ b/MediaBrowser.ClickOnce/ApplicationUpdater.cs @@ -1,11 +1,10 @@ -using MediaBrowser.Model.Tasks; -using System; +using System; using System.ComponentModel; using System.Deployment.Application; using System.Threading; using System.Threading.Tasks; -namespace MediaBrowser.Common.Updates +namespace MediaBrowser.ClickOnce { /// /// Class ApplicationUpdater @@ -20,7 +19,7 @@ namespace MediaBrowser.Common.Updates /// /// The _progress /// - private IProgress _progress; + private IProgress _progress; /// /// Updates the application @@ -29,7 +28,7 @@ namespace MediaBrowser.Common.Updates /// The progress. /// Task{AsyncCompletedEventArgs}. /// Current deployment is not network deployed. - public Task UpdateApplication(CancellationToken cancellationToken, IProgress progress) + public Task UpdateApplication(CancellationToken cancellationToken, IProgress progress) { if (!ApplicationDeployment.IsNetworkDeployed) { @@ -87,7 +86,7 @@ namespace MediaBrowser.Common.Updates /// The instance containing the event data. void deployment_UpdateProgressChanged(object sender, DeploymentProgressChangedEventArgs e) { - _progress.Report(new TaskProgress { PercentComplete = e.ProgressPercentage }); + _progress.Report(e.ProgressPercentage); } } } diff --git a/MediaBrowser.Common/Updates/ClickOnceHelper.cs b/MediaBrowser.ClickOnce/ClickOnceHelper.cs similarity index 82% rename from MediaBrowser.Common/Updates/ClickOnceHelper.cs rename to MediaBrowser.ClickOnce/ClickOnceHelper.cs index 7dd0cf9c57..c86332ccf0 100644 --- a/MediaBrowser.Common/Updates/ClickOnceHelper.cs +++ b/MediaBrowser.ClickOnce/ClickOnceHelper.cs @@ -1,4 +1,5 @@ -using Microsoft.Win32; +using System.Deployment.Application; +using Microsoft.Win32; using System; using System.Diagnostics; using System.IO; @@ -6,7 +7,7 @@ using System.Linq; using System.Reflection; using System.Security.AccessControl; -namespace MediaBrowser.Common.Updates +namespace MediaBrowser.ClickOnce { /// /// Class ClickOnceHelper @@ -43,6 +44,15 @@ namespace MediaBrowser.Common.Updates get { return Assembly.GetExecutingAssembly().Location; } } + /// + /// Gets a value indicating whether this instance is network deployed. + /// + /// true if this instance is network deployed; otherwise, false. + public static bool IsNetworkDeployed + { + get { return ApplicationDeployment.IsNetworkDeployed; } + } + /// /// Gets the name of the publisher. /// @@ -213,5 +223,33 @@ namespace MediaBrowser.Common.Updates }.Start(); } + + /// + /// Configures the click once startup. + /// + /// Name of the publisher. + /// Name of the product. + /// Name of the suite. + /// if set to true [run at startup]. + /// The uninstaller filename. + public static void ConfigureClickOnceStartupIfInstalled(string publisherName, string productName, string suiteName, bool runAtStartup, string uninstallerFilename) + { + if (!ApplicationDeployment.IsNetworkDeployed) + { + return; + } + + var clickOnceHelper = new ClickOnceHelper(publisherName, productName, suiteName); + + if (runAtStartup) + { + clickOnceHelper.UpdateUninstallParameters(uninstallerFilename); + clickOnceHelper.AddShortcutToStartup(); + } + else + { + clickOnceHelper.RemoveShortcutFromStartup(); + } + } } } diff --git a/MediaBrowser.ClickOnce/MediaBrowser.ClickOnce.csproj b/MediaBrowser.ClickOnce/MediaBrowser.ClickOnce.csproj new file mode 100644 index 0000000000..00370bfcdd --- /dev/null +++ b/MediaBrowser.ClickOnce/MediaBrowser.ClickOnce.csproj @@ -0,0 +1,62 @@ + + + + + Debug + AnyCPU + {CC96BF3E-0BDA-4809-BC4B-BB6D418F4A84} + Library + Properties + MediaBrowser.ClickOnce + MediaBrowser.ClickOnce + v4.5 + 512 + + + true + full + false + bin\Debug\ + DEBUG;TRACE + prompt + 4 + + + pdbonly + true + bin\Release\ + TRACE + prompt + 4 + + + + + + + + + + + + + + + + + + + + {7eeeb4bb-f3e8-48fc-b4c5-70f0fff8329b} + MediaBrowser.Model + + + + + \ No newline at end of file diff --git a/MediaBrowser.ClickOnce/Properties/AssemblyInfo.cs b/MediaBrowser.ClickOnce/Properties/AssemblyInfo.cs new file mode 100644 index 0000000000..1faa44e01d --- /dev/null +++ b/MediaBrowser.ClickOnce/Properties/AssemblyInfo.cs @@ -0,0 +1,36 @@ +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. +[assembly: AssemblyTitle("MediaBrowser.ClickOnce")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("")] +[assembly: AssemblyProduct("MediaBrowser.ClickOnce")] +[assembly: AssemblyCopyright("Copyright © 2013")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// Setting ComVisible to false makes the types in this assembly not visible +// to COM components. If you need to access a type in this assembly from +// COM, set the ComVisible attribute to true on that type. +[assembly: ComVisible(false)] + +// The following GUID is for the ID of the typelib if this project is exposed to COM +[assembly: Guid("16e62c11-5009-4212-8c96-fd692479fc5d")] + +// Version information for an assembly consists of the following four values: +// +// Major Version +// Minor Version +// Build Number +// Revision +// +// You can specify all the values or you can default the Build and Revision Numbers +// by using the '*' as shown below: +// [assembly: AssemblyVersion("1.0.*")] +[assembly: AssemblyVersion("1.0.0.0")] +[assembly: AssemblyFileVersion("1.0.0.0")] diff --git a/MediaBrowser.Common/Extensions/BaseExtensions.cs b/MediaBrowser.Common/Extensions/BaseExtensions.cs index e6b9d8ee66..6abe6d4e04 100644 --- a/MediaBrowser.Common/Extensions/BaseExtensions.cs +++ b/MediaBrowser.Common/Extensions/BaseExtensions.cs @@ -5,7 +5,6 @@ using System.Linq; using System.Security.Cryptography; using System.Text; using System.Threading.Tasks; -using System.Windows.Threading; namespace MediaBrowser.Common.Extensions { @@ -46,24 +45,6 @@ namespace MediaBrowser.Common.Extensions return val.Split(new[] { separator }, options); } - /// - /// Invokes an action after a specified delay - /// - /// The dispatcher. - /// The action. - /// The delay ms. - public static void InvokeWithDelay(this Dispatcher dispatcher, Action action, long delayMs) - { - var timer = new DispatcherTimer(DispatcherPriority.Normal, dispatcher); - timer.Interval = TimeSpan.FromMilliseconds(delayMs); - timer.Tick += (sender, args) => - { - timer.Stop(); - action(); - }; - timer.Start(); - } - /// /// Provides a non-blocking method to start a process and wait asynchronously for it to exit /// diff --git a/MediaBrowser.Common/Kernel/BaseKernel.cs b/MediaBrowser.Common/Kernel/BaseKernel.cs index a4ac707494..d172d0a0d0 100644 --- a/MediaBrowser.Common/Kernel/BaseKernel.cs +++ b/MediaBrowser.Common/Kernel/BaseKernel.cs @@ -13,7 +13,6 @@ using System; using System.Collections.Generic; using System.ComponentModel.Composition; using System.ComponentModel.Composition.Hosting; -using System.Deployment.Application; using System.Diagnostics; using System.IO; using System.Linq; @@ -155,12 +154,6 @@ namespace MediaBrowser.Common.Kernel /// true if this instance is first run; otherwise, false. public bool IsFirstRun { get; private set; } - /// - /// The version of the application to display - /// - /// The display version. - public string DisplayVersion { get { return ApplicationVersion.ToString(); } } - /// /// Gets or sets a value indicating whether this instance has changes that require the entire application to restart. /// @@ -325,7 +318,10 @@ namespace MediaBrowser.Common.Kernel /// Gets the log file path. /// /// The log file path. - public string LogFilePath { get; private set; } + public string LogFilePath + { + get { return ApplicationHost.LogFilePath; } + } /// /// Gets the logger. @@ -429,7 +425,7 @@ namespace MediaBrowser.Common.Kernel await ReloadComposableParts().ConfigureAwait(false); DisposeTcpManager(); - TcpManager = new TcpManager(this, Logger); + TcpManager = new TcpManager(ApplicationHost, this, Logger); } /// @@ -482,6 +478,7 @@ namespace MediaBrowser.Common.Kernel protected virtual void ComposeExportedValues(CompositionContainer container) { container.ComposeExportedValue("logger", Logger); + container.ComposeExportedValue("appHost", ApplicationHost); } /// @@ -729,8 +726,8 @@ namespace MediaBrowser.Common.Kernel return new SystemInfo { HasPendingRestart = HasPendingRestart, - Version = DisplayVersion, - IsNetworkDeployed = ApplicationDeployment.IsNetworkDeployed, + Version = ApplicationVersion.ToString(), + IsNetworkDeployed = ApplicationHost.CanSelfUpdate, WebSocketPortNumber = TcpManager.WebSocketPortNumber, SupportsNativeWebSocket = TcpManager.SupportsNativeWebSocket, FailedPluginAssemblies = FailedPluginAssemblies.ToArray() diff --git a/MediaBrowser.Common/Kernel/IApplicationHost.cs b/MediaBrowser.Common/Kernel/IApplicationHost.cs index c1b63c2613..63c63eb3d7 100644 --- a/MediaBrowser.Common/Kernel/IApplicationHost.cs +++ b/MediaBrowser.Common/Kernel/IApplicationHost.cs @@ -1,4 +1,8 @@ - +using MediaBrowser.Model.Updates; +using System; +using System.Threading; +using System.Threading.Tasks; + namespace MediaBrowser.Common.Kernel { /// @@ -15,5 +19,29 @@ namespace MediaBrowser.Common.Kernel /// Reloads the logger. /// void ReloadLogger(); + + /// + /// Gets the log file path. + /// + /// The log file path. + string LogFilePath { get; } + + /// + /// Gets or sets a value indicating whether this instance can self update. + /// + /// true if this instance can self update; otherwise, false. + bool CanSelfUpdate { get; } + + /// + /// Checks for update. + /// + /// Task{CheckForUpdateResult}. + Task CheckForApplicationUpdate(CancellationToken cancellationToken, IProgress progress); + + /// + /// Updates the application. + /// + /// Task. + Task UpdateApplication(CancellationToken cancellationToken, IProgress progress); } } diff --git a/MediaBrowser.Common/Kernel/TcpManager.cs b/MediaBrowser.Common/Kernel/TcpManager.cs index 7fb624f73b..086815cbfd 100644 --- a/MediaBrowser.Common/Kernel/TcpManager.cs +++ b/MediaBrowser.Common/Kernel/TcpManager.cs @@ -64,6 +64,11 @@ namespace MediaBrowser.Common.Kernel /// The _logger /// private readonly ILogger _logger; + + /// + /// The _application host + /// + private readonly IApplicationHost _applicationHost; /// /// The _supports native web socket @@ -108,12 +113,14 @@ namespace MediaBrowser.Common.Kernel /// /// Initializes a new instance of the class. /// + /// The application host. /// The kernel. /// The logger. - public TcpManager(IKernel kernel, ILogger logger) + public TcpManager(IApplicationHost applicationHost, IKernel kernel, ILogger logger) : base(kernel) { _logger = logger; + _applicationHost = applicationHost; if (kernel.IsFirstRun) { @@ -182,7 +189,7 @@ namespace MediaBrowser.Common.Kernel try { - HttpServer = new HttpServer(Kernel.HttpServerUrlPrefix, "Media Browser", Kernel, _logger); + HttpServer = new HttpServer(Kernel.HttpServerUrlPrefix, "Media Browser", _applicationHost, Kernel, _logger); } catch (HttpListenerException ex) { diff --git a/MediaBrowser.Common/MediaBrowser.Common.csproj b/MediaBrowser.Common/MediaBrowser.Common.csproj index b806df856b..c7b162deef 100644 --- a/MediaBrowser.Common/MediaBrowser.Common.csproj +++ b/MediaBrowser.Common/MediaBrowser.Common.csproj @@ -34,7 +34,8 @@ 4 - Resources\Images\Icon.ico + + @@ -94,7 +95,6 @@ - @@ -118,13 +118,8 @@ - - - - - @@ -156,8 +151,6 @@ - - @@ -193,9 +186,6 @@ - - - @@ -216,9 +206,6 @@ Designer - - - diff --git a/MediaBrowser.Common/Net/HttpServer.cs b/MediaBrowser.Common/Net/HttpServer.cs index 184b82c16c..b09c95da03 100644 --- a/MediaBrowser.Common/Net/HttpServer.cs +++ b/MediaBrowser.Common/Net/HttpServer.cs @@ -45,6 +45,12 @@ namespace MediaBrowser.Common.Net /// The kernel. private IKernel Kernel { get; set; } + /// + /// Gets or sets the application host. + /// + /// The application host. + private IApplicationHost ApplicationHost { get; set; } + /// /// This subscribes to HttpListener requests and finds the appropriate BaseHandler to process it /// @@ -67,11 +73,12 @@ namespace MediaBrowser.Common.Net /// /// The URL. /// Name of the product. + /// The application host. /// The kernel. /// The logger. /// The default redirectpath. /// urlPrefix - public HttpServer(string urlPrefix, string serverName, IKernel kernel, ILogger logger, string defaultRedirectpath = null) + public HttpServer(string urlPrefix, string serverName, IApplicationHost applicationHost, IKernel kernel, ILogger logger, string defaultRedirectpath = null) : base() { if (string.IsNullOrEmpty(urlPrefix)) @@ -86,9 +93,14 @@ namespace MediaBrowser.Common.Net { throw new ArgumentNullException("logger"); } + if (applicationHost == null) + { + throw new ArgumentNullException("applicationHost"); + } DefaultRedirectPath = defaultRedirectpath; _logger = logger; + ApplicationHost = applicationHost; EndpointHostConfig.Instance.ServiceStackHandlerFactoryPath = null; EndpointHostConfig.Instance.MetadataRedirectPath = "metadata"; @@ -144,6 +156,7 @@ namespace MediaBrowser.Common.Net container.Register(Kernel); container.Register(_logger); + container.Register(ApplicationHost); foreach (var service in Kernel.RestServices) { diff --git a/MediaBrowser.Common/Net/StaticResult.cs b/MediaBrowser.Common/Net/StaticResult.cs deleted file mode 100644 index 0dd6372cfa..0000000000 --- a/MediaBrowser.Common/Net/StaticResult.cs +++ /dev/null @@ -1,14 +0,0 @@ -using System; -using System.Collections.Generic; -using System.IO; -using System.Linq; -using System.Text; -using System.Threading.Tasks; - -namespace MediaBrowser.Common.Net -{ - public class StaticResult - { - public Stream Stream { get; set; } - } -} diff --git a/MediaBrowser.Common/Resources/Images/Icon.ico b/MediaBrowser.Common/Resources/Images/Icon.ico deleted file mode 100644 index bea939de46ed87bfa851bcab24052e9dde249e02..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 149571 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 OuvYjF /// The current progress. - public TaskProgress CurrentProgress { get; private set; } + public double? CurrentProgress { get; private set; } ///

/// The _triggers @@ -246,7 +246,7 @@ namespace MediaBrowser.Common.ScheduledTasks /// The cancellation token. /// The progress. /// Task. - protected abstract Task ExecuteInternal(CancellationToken cancellationToken, IProgress progress); + protected abstract Task ExecuteInternal(CancellationToken cancellationToken, IProgress progress); /// /// Gets the name of the task @@ -355,7 +355,7 @@ namespace MediaBrowser.Common.ScheduledTasks Logger.Info("Executing {0}", Name); - var progress = new Progress(); + var progress = new Progress(); progress.ProgressChanged += progress_ProgressChanged; @@ -426,7 +426,7 @@ namespace MediaBrowser.Common.ScheduledTasks /// /// The sender. /// The e. - void progress_ProgressChanged(object sender, TaskProgress e) + void progress_ProgressChanged(object sender, double e) { CurrentProgress = e; } diff --git a/MediaBrowser.Common/ScheduledTasks/IScheduledTask.cs b/MediaBrowser.Common/ScheduledTasks/IScheduledTask.cs index a3809c4b9f..95d1edf630 100644 --- a/MediaBrowser.Common/ScheduledTasks/IScheduledTask.cs +++ b/MediaBrowser.Common/ScheduledTasks/IScheduledTask.cs @@ -34,7 +34,7 @@ namespace MediaBrowser.Common.ScheduledTasks /// Gets the current progress. /// /// The current progress. - TaskProgress CurrentProgress { get; } + double? CurrentProgress { get; } /// /// Gets the name of the task diff --git a/MediaBrowser.Common/ScheduledTasks/ScheduledTaskHelpers.cs b/MediaBrowser.Common/ScheduledTasks/ScheduledTaskHelpers.cs index 34421ca1fa..95c4c6a666 100644 --- a/MediaBrowser.Common/ScheduledTasks/ScheduledTaskHelpers.cs +++ b/MediaBrowser.Common/ScheduledTasks/ScheduledTaskHelpers.cs @@ -20,7 +20,7 @@ namespace MediaBrowser.Common.ScheduledTasks return new TaskInfo { Name = task.Name, - CurrentProgress = task.CurrentProgress, + CurrentProgressPercentage = task.CurrentProgress, State = task.State, Id = task.Id, LastExecutionResult = task.LastExecutionResult, diff --git a/MediaBrowser.Common/ScheduledTasks/Tasks/DeleteCacheFileTask.cs b/MediaBrowser.Common/ScheduledTasks/Tasks/DeleteCacheFileTask.cs index 98c6d672a5..2a9bc4a0d8 100644 --- a/MediaBrowser.Common/ScheduledTasks/Tasks/DeleteCacheFileTask.cs +++ b/MediaBrowser.Common/ScheduledTasks/Tasks/DeleteCacheFileTask.cs @@ -33,7 +33,7 @@ namespace MediaBrowser.Common.ScheduledTasks.Tasks /// The cancellation token. /// The progress. /// Task. - protected override Task ExecuteInternal(CancellationToken cancellationToken, IProgress progress) + protected override Task ExecuteInternal(CancellationToken cancellationToken, IProgress progress) { return Task.Run(() => { @@ -51,7 +51,7 @@ namespace MediaBrowser.Common.ScheduledTasks.Tasks /// The directory. /// The min date modified. /// The progress. - private void DeleteCacheFilesFromDirectory(CancellationToken cancellationToken, string directory, DateTime minDateModified, IProgress progress) + private void DeleteCacheFilesFromDirectory(CancellationToken cancellationToken, string directory, DateTime minDateModified, IProgress progress) { var filesToDelete = new DirectoryInfo(directory).EnumerateFileSystemInfos("*", SearchOption.AllDirectories) .Where(f => !f.Attributes.HasFlag(FileAttributes.Directory) && f.LastWriteTimeUtc < minDateModified) @@ -64,7 +64,7 @@ namespace MediaBrowser.Common.ScheduledTasks.Tasks double percent = index; percent /= filesToDelete.Count; - progress.Report(new TaskProgress { Description = file.FullName, PercentComplete = 100 * percent }); + progress.Report(100 * percent); cancellationToken.ThrowIfCancellationRequested(); @@ -73,7 +73,7 @@ namespace MediaBrowser.Common.ScheduledTasks.Tasks index++; } - progress.Report(new TaskProgress { PercentComplete = 100 }); + progress.Report(100); } /// diff --git a/MediaBrowser.Common/ScheduledTasks/Tasks/DeleteLogFileTask.cs b/MediaBrowser.Common/ScheduledTasks/Tasks/DeleteLogFileTask.cs index afb21187ce..a1068a2633 100644 --- a/MediaBrowser.Common/ScheduledTasks/Tasks/DeleteLogFileTask.cs +++ b/MediaBrowser.Common/ScheduledTasks/Tasks/DeleteLogFileTask.cs @@ -33,7 +33,7 @@ namespace MediaBrowser.Common.ScheduledTasks.Tasks /// The cancellation token. /// The progress. /// Task. - protected override Task ExecuteInternal(CancellationToken cancellationToken, IProgress progress) + protected override Task ExecuteInternal(CancellationToken cancellationToken, IProgress progress) { return Task.Run(() => { @@ -51,7 +51,7 @@ namespace MediaBrowser.Common.ScheduledTasks.Tasks double percent = index; percent /= filesToDelete.Count; - progress.Report(new TaskProgress { Description = file.FullName, PercentComplete = 100 * percent }); + progress.Report(100 * percent); cancellationToken.ThrowIfCancellationRequested(); @@ -60,7 +60,7 @@ namespace MediaBrowser.Common.ScheduledTasks.Tasks index++; } - progress.Report(new TaskProgress { PercentComplete = 100 }); + progress.Report(100); }); } diff --git a/MediaBrowser.Common/ScheduledTasks/Tasks/ReloadLoggerTask.cs b/MediaBrowser.Common/ScheduledTasks/Tasks/ReloadLoggerTask.cs index 24aaad57f1..a4f06f2059 100644 --- a/MediaBrowser.Common/ScheduledTasks/Tasks/ReloadLoggerTask.cs +++ b/MediaBrowser.Common/ScheduledTasks/Tasks/ReloadLoggerTask.cs @@ -31,11 +31,11 @@ namespace MediaBrowser.Common.ScheduledTasks.Tasks /// The cancellation token. /// The progress. /// Task. - protected override Task ExecuteInternal(CancellationToken cancellationToken, IProgress progress) + protected override Task ExecuteInternal(CancellationToken cancellationToken, IProgress progress) { cancellationToken.ThrowIfCancellationRequested(); - progress.Report(new TaskProgress { PercentComplete = 0 }); + progress.Report(0); return Task.Run(() => Kernel.ReloadLogger()); } diff --git a/MediaBrowser.Common/ScheduledTasks/Tasks/SystemUpdateTask.cs b/MediaBrowser.Common/ScheduledTasks/Tasks/SystemUpdateTask.cs index a7e3f90a01..f9950424f4 100644 --- a/MediaBrowser.Common/ScheduledTasks/Tasks/SystemUpdateTask.cs +++ b/MediaBrowser.Common/ScheduledTasks/Tasks/SystemUpdateTask.cs @@ -1,10 +1,7 @@ using MediaBrowser.Common.Kernel; -using MediaBrowser.Common.Updates; -using MediaBrowser.Model.Tasks; using System; using System.Collections.Generic; using System.ComponentModel.Composition; -using System.Deployment.Application; using System.Threading; using System.Threading.Tasks; @@ -16,6 +13,21 @@ namespace MediaBrowser.Common.ScheduledTasks.Tasks [Export(typeof(IScheduledTask))] public class SystemUpdateTask : BaseScheduledTask { + /// + /// The _app host + /// + private readonly IApplicationHost _appHost; + + /// + /// Initializes a new instance of the class. + /// + /// The app host. + [ImportingConstructor] + public SystemUpdateTask([Import("appHost")] IApplicationHost appHost) + { + _appHost = appHost; + } + /// /// Creates the triggers that define when the task will run /// @@ -37,26 +49,26 @@ namespace MediaBrowser.Common.ScheduledTasks.Tasks /// The cancellation token. /// The progress. /// Task. - protected override async Task ExecuteInternal(CancellationToken cancellationToken, IProgress progress) + protected override async Task ExecuteInternal(CancellationToken cancellationToken, IProgress progress) { - if (!ApplicationDeployment.IsNetworkDeployed) return; + if (!_appHost.CanSelfUpdate) return; - EventHandler innerProgressHandler = (sender, e) => progress.Report(new TaskProgress { PercentComplete = e.PercentComplete * .1 }); + EventHandler innerProgressHandler = (sender, e) => progress.Report(e * .1); // Create a progress object for the update check - var innerProgress = new Progress(); + var innerProgress = new Progress(); innerProgress.ProgressChanged += innerProgressHandler; - var updateInfo = await new ApplicationUpdateCheck().CheckForApplicationUpdate(cancellationToken, innerProgress).ConfigureAwait(false); + var updateInfo = await _appHost.CheckForApplicationUpdate(cancellationToken, innerProgress).ConfigureAwait(false); // Release the event handler innerProgress.ProgressChanged -= innerProgressHandler; - progress.Report(new TaskProgress { PercentComplete = 10 }); + progress.Report(10); - if (!updateInfo.UpdateAvailable) + if (!updateInfo.IsUpdateAvailable) { - progress.Report(new TaskProgress { PercentComplete = 100 }); + progress.Report(100); return; } @@ -66,12 +78,12 @@ namespace MediaBrowser.Common.ScheduledTasks.Tasks { Logger.Info("Update Revision {0} available. Updating...", updateInfo.AvailableVersion); - innerProgressHandler = (sender, e) => progress.Report(new TaskProgress { PercentComplete = (e.PercentComplete * .9) + .1 }); + innerProgressHandler = (sender, e) => progress.Report((e * .9) + .1); - innerProgress = new Progress(); + innerProgress = new Progress(); innerProgress.ProgressChanged += innerProgressHandler; - await new ApplicationUpdater().UpdateApplication(cancellationToken, innerProgress).ConfigureAwait(false); + await _appHost.UpdateApplication(cancellationToken, innerProgress).ConfigureAwait(false); // Release the event handler innerProgress.ProgressChanged -= innerProgressHandler; @@ -83,7 +95,7 @@ namespace MediaBrowser.Common.ScheduledTasks.Tasks Logger.Info("A new version of Media Browser is available."); } - progress.Report(new TaskProgress { PercentComplete = 100 }); + progress.Report(100); } /// diff --git a/MediaBrowser.Controller/Entities/CollectionFolder.cs b/MediaBrowser.Controller/Entities/CollectionFolder.cs index 33e9f291dd..fbcd2f5895 100644 --- a/MediaBrowser.Controller/Entities/CollectionFolder.cs +++ b/MediaBrowser.Controller/Entities/CollectionFolder.cs @@ -56,7 +56,7 @@ namespace MediaBrowser.Controller.Entities /// The cancellation token. /// if set to true [recursive]. /// Task. - protected override Task ValidateChildrenInternal(IProgress progress, CancellationToken cancellationToken, bool? recursive = null) + protected override Task ValidateChildrenInternal(IProgress progress, CancellationToken cancellationToken, bool? recursive = null) { //we don't directly validate our children //but we do need to clear out the index cache... diff --git a/MediaBrowser.Controller/Entities/Folder.cs b/MediaBrowser.Controller/Entities/Folder.cs index f67934f5d4..bcb0b26be6 100644 --- a/MediaBrowser.Controller/Entities/Folder.cs +++ b/MediaBrowser.Controller/Entities/Folder.cs @@ -612,7 +612,7 @@ namespace MediaBrowser.Controller.Entities /// The cancellation token. /// if set to true [recursive]. /// Task. - public async Task ValidateChildren(IProgress progress, CancellationToken cancellationToken, bool? recursive = null) + public async Task ValidateChildren(IProgress progress, CancellationToken cancellationToken, bool? recursive = null) { cancellationToken.ThrowIfCancellationRequested(); @@ -664,7 +664,7 @@ namespace MediaBrowser.Controller.Entities /// The cancellation token. /// if set to true [recursive]. /// Task. - protected async virtual Task ValidateChildrenInternal(IProgress progress, CancellationToken cancellationToken, bool? recursive = null) + protected async virtual Task ValidateChildrenInternal(IProgress progress, CancellationToken cancellationToken, bool? recursive = null) { // Nothing to do here if (LocationType != LocationType.FileSystem) @@ -681,7 +681,7 @@ namespace MediaBrowser.Controller.Entities if (nonCachedChildren == null) return; //nothing to validate - progress.Report(new TaskProgress { PercentComplete = 5 }); + progress.Report(5); //build a dictionary of the current children we have now by Id so we can compare quickly and easily var currentChildren = ActualChildren.ToDictionary(i => i.Id); @@ -772,13 +772,13 @@ namespace MediaBrowser.Controller.Entities Kernel.Instance.LibraryManager.OnLibraryChanged(changedArgs); } - progress.Report(new TaskProgress { PercentComplete = 15 }); + progress.Report(15); cancellationToken.ThrowIfCancellationRequested(); await RefreshChildren(validChildren, progress, cancellationToken, recursive).ConfigureAwait(false); - progress.Report(new TaskProgress { PercentComplete = 100 }); + progress.Report(100); } /// @@ -789,7 +789,7 @@ namespace MediaBrowser.Controller.Entities /// The cancellation token. /// if set to true [recursive]. /// Task. - private Task RefreshChildren(IEnumerable> children, IProgress progress, CancellationToken cancellationToken, bool? recursive) + private Task RefreshChildren(IEnumerable> children, IProgress progress, CancellationToken cancellationToken, bool? recursive) { var numComplete = 0; @@ -824,7 +824,7 @@ namespace MediaBrowser.Controller.Entities { cancellationToken.ThrowIfCancellationRequested(); - await ((Folder)child).ValidateChildren(new Progress { }, cancellationToken, recursive: recursive).ConfigureAwait(false); + await ((Folder)child).ValidateChildren(new Progress { }, cancellationToken, recursive: recursive).ConfigureAwait(false); } lock (progress) @@ -834,7 +834,7 @@ namespace MediaBrowser.Controller.Entities double percent = numComplete; percent /= list.Count; - progress.Report(new TaskProgress { PercentComplete = (85 * percent) + 15 }); + progress.Report((85 * percent) + 15); } })); @@ -952,7 +952,7 @@ namespace MediaBrowser.Controller.Entities { await base.ChangedExternally().ConfigureAwait(false); - var progress = new Progress { }; + var progress = new Progress { }; await ValidateChildren(progress, CancellationToken.None).ConfigureAwait(false); } diff --git a/MediaBrowser.Controller/Entities/User.cs b/MediaBrowser.Controller/Entities/User.cs index ee9815e62c..f27e8c689d 100644 --- a/MediaBrowser.Controller/Entities/User.cs +++ b/MediaBrowser.Controller/Entities/User.cs @@ -205,7 +205,7 @@ namespace MediaBrowser.Controller.Entities /// The cancellation token. /// The progress. /// Task. - public async Task ValidateMediaLibrary(IProgress progress, CancellationToken cancellationToken) + public async Task ValidateMediaLibrary(IProgress progress, CancellationToken cancellationToken) { Logger.Info("Validating media library for {0}", Name); await RootFolder.RefreshMetadata(cancellationToken).ConfigureAwait(false); @@ -221,7 +221,7 @@ namespace MediaBrowser.Controller.Entities /// The cancellation token. /// The progress. /// Task. - public async Task ValidateCollectionFolders(IProgress progress, CancellationToken cancellationToken) + public async Task ValidateCollectionFolders(IProgress progress, CancellationToken cancellationToken) { Logger.Info("Validating collection folders for {0}", Name); await RootFolder.RefreshMetadata(cancellationToken).ConfigureAwait(false); @@ -279,7 +279,7 @@ namespace MediaBrowser.Controller.Entities RootFolder = null; // Kick off a task to validate the media library - Task.Run(() => ValidateMediaLibrary(new Progress { }, CancellationToken.None)); + Task.Run(() => ValidateMediaLibrary(new Progress { }, CancellationToken.None)); return RefreshMetadata(CancellationToken.None, forceSave: true, forceRefresh: true); } diff --git a/MediaBrowser.Common/Net/NetworkShares.cs b/MediaBrowser.Controller/IO/NetworkShares.cs similarity index 99% rename from MediaBrowser.Common/Net/NetworkShares.cs rename to MediaBrowser.Controller/IO/NetworkShares.cs index 202865b4c1..93edc64471 100644 --- a/MediaBrowser.Common/Net/NetworkShares.cs +++ b/MediaBrowser.Controller/IO/NetworkShares.cs @@ -3,7 +3,7 @@ using System.IO; using System.Collections; using System.Runtime.InteropServices; -namespace MediaBrowser.Common.Net +namespace MediaBrowser.Controller.IO { /// /// Type of share diff --git a/MediaBrowser.Controller/Library/LibraryManager.cs b/MediaBrowser.Controller/Library/LibraryManager.cs index 95a11e8fe5..4087f9ef86 100644 --- a/MediaBrowser.Controller/Library/LibraryManager.cs +++ b/MediaBrowser.Controller/Library/LibraryManager.cs @@ -369,7 +369,7 @@ namespace MediaBrowser.Controller.Library /// The cancellation token. /// The progress. /// Task. - internal async Task ValidatePeople(CancellationToken cancellationToken, IProgress progress) + internal async Task ValidatePeople(CancellationToken cancellationToken, IProgress progress) { // Clear the IBN cache ImagesByNameItemCache.Clear(); @@ -422,14 +422,14 @@ namespace MediaBrowser.Controller.Library double percent = numComplete; percent /= people.Count; - progress.Report(new TaskProgress { PercentComplete = 100 * percent }); + progress.Report(100 * percent); } })); } await Task.WhenAll(tasks).ConfigureAwait(false); - progress.Report(new TaskProgress { PercentComplete = 100 }); + progress.Report(100); _logger.Info("People validation complete"); } @@ -440,17 +440,17 @@ namespace MediaBrowser.Controller.Library /// The progress. /// The cancellation token. /// Task. - internal async Task ValidateMediaLibrary(IProgress progress, CancellationToken cancellationToken) + internal async Task ValidateMediaLibrary(IProgress progress, CancellationToken cancellationToken) { _logger.Info("Validating media library"); await Kernel.RootFolder.RefreshMetadata(cancellationToken).ConfigureAwait(false); // Start by just validating the children of the root, but go no further - await Kernel.RootFolder.ValidateChildren(new Progress { }, cancellationToken, recursive: false); + await Kernel.RootFolder.ValidateChildren(new Progress { }, cancellationToken, recursive: false); // Validate only the collection folders for each user, just to make them available as quickly as possible - var userCollectionFolderTasks = Kernel.Users.AsParallel().Select(user => user.ValidateCollectionFolders(new Progress { }, cancellationToken)); + var userCollectionFolderTasks = Kernel.Users.AsParallel().Select(user => user.ValidateCollectionFolders(new Progress { }, cancellationToken)); await Task.WhenAll(userCollectionFolderTasks).ConfigureAwait(false); // Now validate the entire media library @@ -458,7 +458,7 @@ namespace MediaBrowser.Controller.Library foreach (var user in Kernel.Users) { - await user.ValidateMediaLibrary(new Progress { }, cancellationToken).ConfigureAwait(false); + await user.ValidateMediaLibrary(new Progress { }, cancellationToken).ConfigureAwait(false); } } diff --git a/MediaBrowser.Controller/MediaBrowser.Controller.csproj b/MediaBrowser.Controller/MediaBrowser.Controller.csproj index c2b11ae320..0bf3e6c1f5 100644 --- a/MediaBrowser.Controller/MediaBrowser.Controller.csproj +++ b/MediaBrowser.Controller/MediaBrowser.Controller.csproj @@ -67,7 +67,6 @@ - @@ -106,6 +105,7 @@ + diff --git a/MediaBrowser.Controller/ScheduledTasks/ChapterImagesTask.cs b/MediaBrowser.Controller/ScheduledTasks/ChapterImagesTask.cs index 21f1bce5ac..d3d30ed771 100644 --- a/MediaBrowser.Controller/ScheduledTasks/ChapterImagesTask.cs +++ b/MediaBrowser.Controller/ScheduledTasks/ChapterImagesTask.cs @@ -31,7 +31,7 @@ namespace MediaBrowser.Controller.ScheduledTasks /// The cancellation token. /// The progress. /// Task. - protected override Task ExecuteInternal(CancellationToken cancellationToken, IProgress progress) + protected override Task ExecuteInternal(CancellationToken cancellationToken, IProgress progress) { var videos = Kernel.RootFolder.RecursiveChildren.OfType