Browse Source

isolated clickonce dependancies

LukePulverenti 12 years ago
parent
commit
868a7ce9c8
58 changed files with 505 additions and 244 deletions
  1. 1 0
      MediaBrowser.Api/EnvironmentService.cs
  2. 5 4
      MediaBrowser.Api/MediaBrowser.Api.csproj
  3. 9 4
      MediaBrowser.Api/PackageService.cs
  4. 1 1
      MediaBrowser.Api/ScheduledTasks/ScheduledTaskService.cs
  5. 1 1
      MediaBrowser.Api/ScheduledTasks/ScheduledTasksWebSocketListener.cs
  6. 1 1
      MediaBrowser.Api/WebSocket/LogFileWebSocketListener.cs
  7. 4 3
      MediaBrowser.Api/WebSocket/SystemInfoWebSocketListener.cs
  8. 23 9
      MediaBrowser.ClickOnce/ApplicationUpdateCheck.cs
  9. 5 6
      MediaBrowser.ClickOnce/ApplicationUpdater.cs
  10. 40 2
      MediaBrowser.ClickOnce/ClickOnceHelper.cs
  11. 62 0
      MediaBrowser.ClickOnce/MediaBrowser.ClickOnce.csproj
  12. 36 0
      MediaBrowser.ClickOnce/Properties/AssemblyInfo.cs
  13. 0 19
      MediaBrowser.Common/Extensions/BaseExtensions.cs
  14. 8 11
      MediaBrowser.Common/Kernel/BaseKernel.cs
  15. 29 1
      MediaBrowser.Common/Kernel/IApplicationHost.cs
  16. 9 2
      MediaBrowser.Common/Kernel/TcpManager.cs
  17. 2 15
      MediaBrowser.Common/MediaBrowser.Common.csproj
  18. 14 1
      MediaBrowser.Common/Net/HttpServer.cs
  19. 0 14
      MediaBrowser.Common/Net/StaticResult.cs
  20. BIN
      MediaBrowser.Common/Resources/Images/Icon.ico
  21. 4 4
      MediaBrowser.Common/ScheduledTasks/BaseScheduledTask.cs
  22. 1 1
      MediaBrowser.Common/ScheduledTasks/IScheduledTask.cs
  23. 1 1
      MediaBrowser.Common/ScheduledTasks/ScheduledTaskHelpers.cs
  24. 4 4
      MediaBrowser.Common/ScheduledTasks/Tasks/DeleteCacheFileTask.cs
  25. 3 3
      MediaBrowser.Common/ScheduledTasks/Tasks/DeleteLogFileTask.cs
  26. 2 2
      MediaBrowser.Common/ScheduledTasks/Tasks/ReloadLoggerTask.cs
  27. 27 15
      MediaBrowser.Common/ScheduledTasks/Tasks/SystemUpdateTask.cs
  28. 1 1
      MediaBrowser.Controller/Entities/CollectionFolder.cs
  29. 9 9
      MediaBrowser.Controller/Entities/Folder.cs
  30. 3 3
      MediaBrowser.Controller/Entities/User.cs
  31. 1 1
      MediaBrowser.Controller/IO/NetworkShares.cs
  32. 7 7
      MediaBrowser.Controller/Library/LibraryManager.cs
  33. 1 1
      MediaBrowser.Controller/MediaBrowser.Controller.csproj
  34. 2 2
      MediaBrowser.Controller/ScheduledTasks/ChapterImagesTask.cs
  35. 2 2
      MediaBrowser.Controller/ScheduledTasks/ImageCleanupTask.cs
  36. 1 1
      MediaBrowser.Controller/ScheduledTasks/PeopleValidationTask.cs
  37. 5 5
      MediaBrowser.Controller/ScheduledTasks/PluginUpdateTask.cs
  38. 2 2
      MediaBrowser.Controller/ScheduledTasks/RefreshMediaLibraryTask.cs
  39. 1 1
      MediaBrowser.Model/MediaBrowser.Model.csproj
  40. 1 1
      MediaBrowser.Model/Tasks/TaskInfo.cs
  41. 0 22
      MediaBrowser.Model/Tasks/TaskProgress.cs
  42. 22 0
      MediaBrowser.Model/Updates/CheckForUpdateResult.cs
  43. 4 4
      MediaBrowser.Plugins.Trailers/ScheduledTasks/CurrentTrailerDownloadTask.cs
  44. 3 3
      MediaBrowser.Server.Uninstall/MediaBrowser.Server.Uninstall.csproj
  45. 1 1
      MediaBrowser.Server.Uninstall/Program.cs
  46. 36 20
      MediaBrowser.ServerApplication/App.xaml.cs
  47. 1 1
      MediaBrowser.ServerApplication/LibraryExplorer.xaml.cs
  48. 4 1
      MediaBrowser.ServerApplication/MediaBrowser.ServerApplication.csproj
  49. 3 3
      MediaBrowser.UI.Uninstall/MediaBrowser.UI.Uninstall.csproj
  50. 1 1
      MediaBrowser.UI.Uninstall/Program.cs
  51. 12 0
      MediaBrowser.UI.sln
  52. 39 23
      MediaBrowser.UI/App.xaml.cs
  53. 26 0
      MediaBrowser.UI/Extensions/Extensions.cs
  54. 1 0
      MediaBrowser.UI/MainWindow.xaml.cs
  55. 5 1
      MediaBrowser.UI/MediaBrowser.UI.csproj
  56. 2 2
      MediaBrowser.WebDashboard/Html/scripts/DashboardPage.js
  57. 1 2
      MediaBrowser.WebDashboard/Html/scripts/ScheduledTasksPage.js
  58. 16 0
      MediaBrowser.sln

+ 1 - 0
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;

+ 5 - 4
MediaBrowser.Api/MediaBrowser.Api.csproj

@@ -66,14 +66,11 @@
     <Reference Include="System" />
     <Reference Include="System.ComponentModel.Composition" />
     <Reference Include="System.Core" />
-    <Reference Include="System.Deployment" />
     <Reference Include="System.Drawing" />
     <Reference Include="System.Runtime.Serialization" />
-    <Reference Include="System.Xml.Linq" />
-    <Reference Include="System.Data.DataSetExtensions" />
     <Reference Include="Microsoft.CSharp" />
     <Reference Include="System.Data" />
-    <Reference Include="System.Xml" />
+    <Reference Include="System.XML" />
   </ItemGroup>
   <ItemGroup>
     <Compile Include="ApiService.cs" />
@@ -87,6 +84,8 @@
     <Compile Include="LocalizationService.cs" />
     <Compile Include="PackageService.cs" />
     <Compile Include="PluginService.cs" />
+    <Compile Include="ScheduledTasks\ScheduledTaskService.cs" />
+    <Compile Include="ScheduledTasks\ScheduledTasksWebSocketListener.cs" />
     <Compile Include="SystemService.cs" />
     <Compile Include="Streaming\AudioHandler.cs" />
     <Compile Include="Streaming\BaseHlsPlaylistHandler.cs" />
@@ -108,6 +107,8 @@
     <Compile Include="Plugin.cs" />
     <Compile Include="Properties\AssemblyInfo.cs" />
     <Compile Include="WeatherService.cs" />
+    <Compile Include="WebSocket\LogFileWebSocketListener.cs" />
+    <Compile Include="WebSocket\SystemInfoWebSocketListener.cs" />
   </ItemGroup>
   <ItemGroup>
     <ProjectReference Include="..\MediaBrowser.Common\MediaBrowser.Common.csproj">

+ 9 - 4
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
     {
+        /// <summary>
+        /// Gets or sets the application host.
+        /// </summary>
+        /// <value>The application host.</value>
+        public IApplicationHost ApplicationHost { get; set; }
+
         /// <summary>
         /// Gets the specified request.
         /// </summary>
@@ -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<TaskProgress> { }).Result;
+                var updateCheckResult = ApplicationHost.CheckForApplicationUpdate(CancellationToken.None, new Progress<double> { }).Result;
 
-                if (updateCheckResult.UpdateAvailable)
+                if (updateCheckResult.IsUpdateAvailable)
                 {
                     result.Add(new PackageVersionInfo
                     {

+ 1 - 1
MediaBrowser.Common/Api/ScheduledTasks/ScheduledTaskService.cs → 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
 {
     /// <summary>
     /// Class GetScheduledTask

+ 1 - 1
MediaBrowser.Common/Api/ScheduledTasks/ScheduledTasksWebSocketListener.cs → 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
 {
     /// <summary>
     /// Class ScheduledTasksWebSocketListener

+ 1 - 1
MediaBrowser.Common/Api/Logging/LogFileWebSocketListener.cs → 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
 {
     /// <summary>
     /// Class ScheduledTasksWebSocketListener

+ 4 - 3
MediaBrowser.Common/Api/SystemInfoWebSocketListener.cs → 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
 {
     /// <summary>
     /// Class SystemInfoWebSocketListener
     /// </summary>
     [Export(typeof(IWebSocketListener))]
-    public class SystemInfoWebSocketListener : BasePeriodicWebSocketListener<IKernel, Model.System.SystemInfo, object>
+    public class SystemInfoWebSocketListener : BasePeriodicWebSocketListener<IKernel, SystemInfo, object>
     {
         /// <summary>
         /// Gets the name.
@@ -36,7 +37,7 @@ namespace MediaBrowser.Common.Api
         /// </summary>
         /// <param name="state">The state.</param>
         /// <returns>Task{SystemInfo}.</returns>
-        protected override Task<Model.System.SystemInfo> GetDataToSend(object state)
+        protected override Task<SystemInfo> GetDataToSend(object state)
         {
             return Task.FromResult(Kernel.GetSystemInfo());
         }

+ 23 - 9
MediaBrowser.Common/Updates/ApplicationUpdateCheck.cs → 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
 {
     /// <summary>
     /// Class ApplicationUpdateCheck
@@ -14,12 +14,12 @@ namespace MediaBrowser.Common.Updates
         /// <summary>
         /// The _task completion source
         /// </summary>
-        private TaskCompletionSource<CheckForUpdateCompletedEventArgs> _taskCompletionSource;
+        private TaskCompletionSource<CheckForUpdateResult> _taskCompletionSource;
 
         /// <summary>
         /// The _progress
         /// </summary>
-        private IProgress<TaskProgress> _progress;
+        private IProgress<double> _progress;
 
         /// <summary>
         /// Checks for application update.
@@ -28,7 +28,7 @@ namespace MediaBrowser.Common.Updates
         /// <param name="progress">The progress.</param>
         /// <returns>Task{CheckForUpdateCompletedEventArgs}.</returns>
         /// <exception cref="System.InvalidOperationException">Current deployment is not a ClickOnce deployment</exception>
-        public Task<CheckForUpdateCompletedEventArgs> CheckForApplicationUpdate(CancellationToken cancellationToken, IProgress<TaskProgress> progress)
+        public Task<CheckForUpdateResult> CheckForApplicationUpdate(CancellationToken cancellationToken, IProgress<double> progress)
         {
             if (!ApplicationDeployment.IsNetworkDeployed)
             {
@@ -36,8 +36,8 @@ namespace MediaBrowser.Common.Updates
             }
 
             _progress = progress;
-            
-            _taskCompletionSource = new TaskCompletionSource<CheckForUpdateCompletedEventArgs>();
+
+            _taskCompletionSource = new TaskCompletionSource<CheckForUpdateResult>();
 
             var deployment = ApplicationDeployment.CurrentDeployment;
 
@@ -53,6 +53,20 @@ namespace MediaBrowser.Common.Updates
             return _taskCompletionSource.Task;
         }
 
+        /// <summary>
+        /// To the result.
+        /// </summary>
+        /// <param name="args">The <see cref="CheckForUpdateCompletedEventArgs" /> instance containing the event data.</param>
+        /// <returns>CheckForUpdateResult.</returns>
+        private CheckForUpdateResult ToResult(CheckForUpdateCompletedEventArgs args)
+        {
+            return new CheckForUpdateResult
+            {
+                AvailableVersion = args.AvailableVersion,
+                IsUpdateAvailable = args.UpdateAvailable
+            };
+        }
+
         /// <summary>
         /// Handles the CheckForUpdateCompleted event of the deployment control.
         /// </summary>
@@ -75,7 +89,7 @@ namespace MediaBrowser.Common.Updates
             }
             else
             {
-                _taskCompletionSource.SetResult(e);
+                _taskCompletionSource.SetResult(ToResult(e));
             }
         }
 
@@ -86,7 +100,7 @@ namespace MediaBrowser.Common.Updates
         /// <param name="e">The <see cref="DeploymentProgressChangedEventArgs" /> instance containing the event data.</param>
         void deployment_CheckForUpdateProgressChanged(object sender, DeploymentProgressChangedEventArgs e)
         {
-            _progress.Report(new TaskProgress { PercentComplete = e.ProgressPercentage });
+            _progress.Report(e.ProgressPercentage);
         }
     }
 }

+ 5 - 6
MediaBrowser.Common/Updates/ApplicationUpdater.cs → 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
 {
     /// <summary>
     /// Class ApplicationUpdater
@@ -20,7 +19,7 @@ namespace MediaBrowser.Common.Updates
         /// <summary>
         /// The _progress
         /// </summary>
-        private IProgress<TaskProgress> _progress;
+        private IProgress<double> _progress;
 
         /// <summary>
         /// Updates the application
@@ -29,7 +28,7 @@ namespace MediaBrowser.Common.Updates
         /// <param name="progress">The progress.</param>
         /// <returns>Task{AsyncCompletedEventArgs}.</returns>
         /// <exception cref="System.InvalidOperationException">Current deployment is not network deployed.</exception>
-        public Task<AsyncCompletedEventArgs> UpdateApplication(CancellationToken cancellationToken, IProgress<TaskProgress> progress)
+        public Task<AsyncCompletedEventArgs> UpdateApplication(CancellationToken cancellationToken, IProgress<double> progress)
         {
             if (!ApplicationDeployment.IsNetworkDeployed)
             {
@@ -87,7 +86,7 @@ namespace MediaBrowser.Common.Updates
         /// <param name="e">The <see cref="DeploymentProgressChangedEventArgs" /> instance containing the event data.</param>
         void deployment_UpdateProgressChanged(object sender, DeploymentProgressChangedEventArgs e)
         {
-            _progress.Report(new TaskProgress { PercentComplete = e.ProgressPercentage });
+            _progress.Report(e.ProgressPercentage);
         }
     }
 }

+ 40 - 2
MediaBrowser.Common/Updates/ClickOnceHelper.cs → 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
 {
     /// <summary>
     /// Class ClickOnceHelper
@@ -43,6 +44,15 @@ namespace MediaBrowser.Common.Updates
             get { return Assembly.GetExecutingAssembly().Location; }
         }
 
+        /// <summary>
+        /// Gets a value indicating whether this instance is network deployed.
+        /// </summary>
+        /// <value><c>true</c> if this instance is network deployed; otherwise, <c>false</c>.</value>
+        public static bool IsNetworkDeployed
+        {
+            get { return ApplicationDeployment.IsNetworkDeployed; }
+        }
+
         /// <summary>
         /// Gets the name of the publisher.
         /// </summary>
@@ -213,5 +223,33 @@ namespace MediaBrowser.Common.Updates
 
             }.Start();
         }
+
+        /// <summary>
+        /// Configures the click once startup.
+        /// </summary>
+        /// <param name="publisherName">Name of the publisher.</param>
+        /// <param name="productName">Name of the product.</param>
+        /// <param name="suiteName">Name of the suite.</param>
+        /// <param name="runAtStartup">if set to <c>true</c> [run at startup].</param>
+        /// <param name="uninstallerFilename">The uninstaller filename.</param>
+        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();
+            }
+        }
     }
 }

+ 62 - 0
MediaBrowser.ClickOnce/MediaBrowser.ClickOnce.csproj

@@ -0,0 +1,62 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="4.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+  <Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
+  <PropertyGroup>
+    <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
+    <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
+    <ProjectGuid>{CC96BF3E-0BDA-4809-BC4B-BB6D418F4A84}</ProjectGuid>
+    <OutputType>Library</OutputType>
+    <AppDesignerFolder>Properties</AppDesignerFolder>
+    <RootNamespace>MediaBrowser.ClickOnce</RootNamespace>
+    <AssemblyName>MediaBrowser.ClickOnce</AssemblyName>
+    <TargetFrameworkVersion>v4.5</TargetFrameworkVersion>
+    <FileAlignment>512</FileAlignment>
+  </PropertyGroup>
+  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
+    <DebugSymbols>true</DebugSymbols>
+    <DebugType>full</DebugType>
+    <Optimize>false</Optimize>
+    <OutputPath>bin\Debug\</OutputPath>
+    <DefineConstants>DEBUG;TRACE</DefineConstants>
+    <ErrorReport>prompt</ErrorReport>
+    <WarningLevel>4</WarningLevel>
+  </PropertyGroup>
+  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
+    <DebugType>pdbonly</DebugType>
+    <Optimize>true</Optimize>
+    <OutputPath>bin\Release\</OutputPath>
+    <DefineConstants>TRACE</DefineConstants>
+    <ErrorReport>prompt</ErrorReport>
+    <WarningLevel>4</WarningLevel>
+  </PropertyGroup>
+  <ItemGroup>
+    <Reference Include="System" />
+    <Reference Include="System.Core" />
+    <Reference Include="System.Deployment" />
+    <Reference Include="System.Xml.Linq" />
+    <Reference Include="System.Data.DataSetExtensions" />
+    <Reference Include="Microsoft.CSharp" />
+    <Reference Include="System.Data" />
+    <Reference Include="System.Xml" />
+  </ItemGroup>
+  <ItemGroup>
+    <Compile Include="ApplicationUpdateCheck.cs" />
+    <Compile Include="ApplicationUpdater.cs" />
+    <Compile Include="ClickOnceHelper.cs" />
+    <Compile Include="Properties\AssemblyInfo.cs" />
+  </ItemGroup>
+  <ItemGroup>
+    <ProjectReference Include="..\MediaBrowser.Model\MediaBrowser.Model.csproj">
+      <Project>{7eeeb4bb-f3e8-48fc-b4c5-70f0fff8329b}</Project>
+      <Name>MediaBrowser.Model</Name>
+    </ProjectReference>
+  </ItemGroup>
+  <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
+  <!-- To modify your build process, add your task inside one of the targets below and uncomment it. 
+       Other similar extension points exist, see Microsoft.Common.targets.
+  <Target Name="BeforeBuild">
+  </Target>
+  <Target Name="AfterBuild">
+  </Target>
+  -->
+</Project>

+ 36 - 0
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")]

+ 0 - 19
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);
         }
 
-        /// <summary>
-        /// Invokes an action after a specified delay
-        /// </summary>
-        /// <param name="dispatcher">The dispatcher.</param>
-        /// <param name="action">The action.</param>
-        /// <param name="delayMs">The delay ms.</param>
-        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();
-        }
-
         /// <summary>
         /// Provides a non-blocking method to start a process and wait asynchronously for it to exit
         /// </summary>

+ 8 - 11
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
         /// <value><c>true</c> if this instance is first run; otherwise, <c>false</c>.</value>
         public bool IsFirstRun { get; private set; }
 
-        /// <summary>
-        /// The version of the application to display
-        /// </summary>
-        /// <value>The display version.</value>
-        public string DisplayVersion { get { return ApplicationVersion.ToString(); } }
-
         /// <summary>
         /// Gets or sets a value indicating whether this instance has changes that require the entire application to restart.
         /// </summary>
@@ -325,7 +318,10 @@ namespace MediaBrowser.Common.Kernel
         /// Gets the log file path.
         /// </summary>
         /// <value>The log file path.</value>
-        public string LogFilePath { get; private set; }
+        public string LogFilePath
+        {
+            get { return ApplicationHost.LogFilePath; }
+        }
 
         /// <summary>
         /// 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);
         }
 
         /// <summary>
@@ -482,6 +478,7 @@ namespace MediaBrowser.Common.Kernel
         protected virtual void ComposeExportedValues(CompositionContainer container)
         {
             container.ComposeExportedValue("logger", Logger);
+            container.ComposeExportedValue("appHost", ApplicationHost);
         }
 
         /// <summary>
@@ -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()

+ 29 - 1
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
 {
     /// <summary>
@@ -15,5 +19,29 @@ namespace MediaBrowser.Common.Kernel
         /// Reloads the logger.
         /// </summary>
         void ReloadLogger();
+
+        /// <summary>
+        /// Gets the log file path.
+        /// </summary>
+        /// <value>The log file path.</value>
+        string LogFilePath { get; }
+
+        /// <summary>
+        /// Gets or sets a value indicating whether this instance can self update.
+        /// </summary>
+        /// <value><c>true</c> if this instance can self update; otherwise, <c>false</c>.</value>
+        bool CanSelfUpdate { get; }
+
+        /// <summary>
+        /// Checks for update.
+        /// </summary>
+        /// <returns>Task{CheckForUpdateResult}.</returns>
+        Task<CheckForUpdateResult> CheckForApplicationUpdate(CancellationToken cancellationToken, IProgress<double> progress);
+
+        /// <summary>
+        /// Updates the application.
+        /// </summary>
+        /// <returns>Task.</returns>
+        Task UpdateApplication(CancellationToken cancellationToken, IProgress<double> progress);
     }
 }

+ 9 - 2
MediaBrowser.Common/Kernel/TcpManager.cs

@@ -64,6 +64,11 @@ namespace MediaBrowser.Common.Kernel
         /// The _logger
         /// </summary>
         private readonly ILogger _logger;
+
+        /// <summary>
+        /// The _application host
+        /// </summary>
+        private readonly IApplicationHost _applicationHost;
         
         /// <summary>
         /// The _supports native web socket
@@ -108,12 +113,14 @@ namespace MediaBrowser.Common.Kernel
         /// <summary>
         /// Initializes a new instance of the <see cref="TcpManager" /> class.
         /// </summary>
+        /// <param name="applicationHost">The application host.</param>
         /// <param name="kernel">The kernel.</param>
         /// <param name="logger">The logger.</param>
-        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)
             {

+ 2 - 15
MediaBrowser.Common/MediaBrowser.Common.csproj

@@ -34,7 +34,8 @@
     <WarningLevel>4</WarningLevel>
   </PropertyGroup>
   <PropertyGroup>
-    <ApplicationIcon>Resources\Images\Icon.ico</ApplicationIcon>
+    <ApplicationIcon>
+    </ApplicationIcon>
   </PropertyGroup>
   <ItemGroup>
     <Reference Include="Alchemy">
@@ -94,7 +95,6 @@
     <Reference Include="System.ComponentModel.Composition" />
     <Reference Include="System.Configuration" />
     <Reference Include="System.Core" />
-    <Reference Include="System.Deployment" />
     <Reference Include="System.Management" />
     <Reference Include="System.Net" />
     <Reference Include="System.Net.Http" />
@@ -118,13 +118,8 @@
     <Reference Include="Microsoft.CSharp" />
     <Reference Include="System.Data" />
     <Reference Include="System.Xml" />
-    <Reference Include="WindowsBase" />
   </ItemGroup>
   <ItemGroup>
-    <Compile Include="Api\Logging\LogFileWebSocketListener.cs" />
-    <Compile Include="Api\ScheduledTasks\ScheduledTaskService.cs" />
-    <Compile Include="Api\ScheduledTasks\ScheduledTasksWebSocketListener.cs" />
-    <Compile Include="Api\SystemInfoWebSocketListener.cs" />
     <Compile Include="Events\EventHelper.cs" />
     <Compile Include="Extensions\BaseExtensions.cs" />
     <Compile Include="Events\GenericEventArgs.cs" />
@@ -156,8 +151,6 @@
     <Compile Include="Net\MimeTypes.cs" />
     <Compile Include="Net\NativeWebSocket.cs" />
     <Compile Include="Net\NetUtils.cs" />
-    <Compile Include="Net\NetworkShares.cs" />
-    <Compile Include="Net\StaticResult.cs" />
     <Compile Include="Net\UdpServer.cs" />
     <Compile Include="Net\WebSocketConnection.cs" />
     <Compile Include="Plugins\BaseUiPlugin.cs" />
@@ -193,9 +186,6 @@
     <Compile Include="ScheduledTasks\IntervalTrigger.cs" />
     <Compile Include="ScheduledTasks\IScheduledTask.cs" />
     <Compile Include="ScheduledTasks\WeeklyTrigger.cs" />
-    <Compile Include="Updates\ApplicationUpdateCheck.cs" />
-    <Compile Include="Updates\ApplicationUpdater.cs" />
-    <Compile Include="Updates\ClickOnceHelper.cs" />
     <Compile Include="Win32\NativeMethods.cs" />
   </ItemGroup>
   <ItemGroup>
@@ -216,9 +206,6 @@
       <SubType>Designer</SubType>
     </EmbeddedResource>
   </ItemGroup>
-  <ItemGroup>
-    <Resource Include="Resources\Images\Icon.ico" />
-  </ItemGroup>
   <ItemGroup>
     <Resource Include="README.txt" />
     <Content Include="swagger-ui\css\screen.css" />

+ 14 - 1
MediaBrowser.Common/Net/HttpServer.cs

@@ -45,6 +45,12 @@ namespace MediaBrowser.Common.Net
         /// <value>The kernel.</value>
         private IKernel Kernel { get; set; }
 
+        /// <summary>
+        /// Gets or sets the application host.
+        /// </summary>
+        /// <value>The application host.</value>
+        private IApplicationHost ApplicationHost { get; set; }
+        
         /// <summary>
         /// This subscribes to HttpListener requests and finds the appropriate BaseHandler to process it
         /// </summary>
@@ -67,11 +73,12 @@ namespace MediaBrowser.Common.Net
         /// </summary>
         /// <param name="urlPrefix">The URL.</param>
         /// <param name="serverName">Name of the product.</param>
+        /// <param name="applicationHost">The application host.</param>
         /// <param name="kernel">The kernel.</param>
         /// <param name="logger">The logger.</param>
         /// <param name="defaultRedirectpath">The default redirectpath.</param>
         /// <exception cref="System.ArgumentNullException">urlPrefix</exception>
-        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)
             {

+ 0 - 14
MediaBrowser.Common/Net/StaticResult.cs

@@ -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; }
-    }
-}

BIN
MediaBrowser.Common/Resources/Images/Icon.ico


+ 4 - 4
MediaBrowser.Common/ScheduledTasks/BaseScheduledTask.cs

@@ -171,7 +171,7 @@ namespace MediaBrowser.Common.ScheduledTasks
         /// Gets the current progress.
         /// </summary>
         /// <value>The current progress.</value>
-        public TaskProgress CurrentProgress { get; private set; }
+        public double? CurrentProgress { get; private set; }
 
         /// <summary>
         /// The _triggers
@@ -246,7 +246,7 @@ namespace MediaBrowser.Common.ScheduledTasks
         /// <param name="cancellationToken">The cancellation token.</param>
         /// <param name="progress">The progress.</param>
         /// <returns>Task.</returns>
-        protected abstract Task ExecuteInternal(CancellationToken cancellationToken, IProgress<TaskProgress> progress);
+        protected abstract Task ExecuteInternal(CancellationToken cancellationToken, IProgress<double> progress);
 
         /// <summary>
         /// Gets the name of the task
@@ -355,7 +355,7 @@ namespace MediaBrowser.Common.ScheduledTasks
 
             Logger.Info("Executing {0}", Name);
 
-            var progress = new Progress<TaskProgress>();
+            var progress = new Progress<double>();
 
             progress.ProgressChanged += progress_ProgressChanged;
 
@@ -426,7 +426,7 @@ namespace MediaBrowser.Common.ScheduledTasks
         /// </summary>
         /// <param name="sender">The sender.</param>
         /// <param name="e">The e.</param>
-        void progress_ProgressChanged(object sender, TaskProgress e)
+        void progress_ProgressChanged(object sender, double e)
         {
             CurrentProgress = e;
         }

+ 1 - 1
MediaBrowser.Common/ScheduledTasks/IScheduledTask.cs

@@ -34,7 +34,7 @@ namespace MediaBrowser.Common.ScheduledTasks
         /// Gets the current progress.
         /// </summary>
         /// <value>The current progress.</value>
-        TaskProgress CurrentProgress { get; }
+        double? CurrentProgress { get; }
 
         /// <summary>
         /// Gets the name of the task

+ 1 - 1
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,

+ 4 - 4
MediaBrowser.Common/ScheduledTasks/Tasks/DeleteCacheFileTask.cs

@@ -33,7 +33,7 @@ namespace MediaBrowser.Common.ScheduledTasks.Tasks
         /// <param name="cancellationToken">The cancellation token.</param>
         /// <param name="progress">The progress.</param>
         /// <returns>Task.</returns>
-        protected override Task ExecuteInternal(CancellationToken cancellationToken, IProgress<TaskProgress> progress)
+        protected override Task ExecuteInternal(CancellationToken cancellationToken, IProgress<double> progress)
         {
             return Task.Run(() =>
             {
@@ -51,7 +51,7 @@ namespace MediaBrowser.Common.ScheduledTasks.Tasks
         /// <param name="directory">The directory.</param>
         /// <param name="minDateModified">The min date modified.</param>
         /// <param name="progress">The progress.</param>
-        private void DeleteCacheFilesFromDirectory(CancellationToken cancellationToken, string directory, DateTime minDateModified, IProgress<TaskProgress> progress)
+        private void DeleteCacheFilesFromDirectory(CancellationToken cancellationToken, string directory, DateTime minDateModified, IProgress<double> 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);
         }
 
         /// <summary>

+ 3 - 3
MediaBrowser.Common/ScheduledTasks/Tasks/DeleteLogFileTask.cs

@@ -33,7 +33,7 @@ namespace MediaBrowser.Common.ScheduledTasks.Tasks
         /// <param name="cancellationToken">The cancellation token.</param>
         /// <param name="progress">The progress.</param>
         /// <returns>Task.</returns>
-        protected override Task ExecuteInternal(CancellationToken cancellationToken, IProgress<TaskProgress> progress)
+        protected override Task ExecuteInternal(CancellationToken cancellationToken, IProgress<double> 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);
             });
         }
 

+ 2 - 2
MediaBrowser.Common/ScheduledTasks/Tasks/ReloadLoggerTask.cs

@@ -31,11 +31,11 @@ namespace MediaBrowser.Common.ScheduledTasks.Tasks
         /// <param name="cancellationToken">The cancellation token.</param>
         /// <param name="progress">The progress.</param>
         /// <returns>Task.</returns>
-        protected override Task ExecuteInternal(CancellationToken cancellationToken, IProgress<TaskProgress> progress)
+        protected override Task ExecuteInternal(CancellationToken cancellationToken, IProgress<double> progress)
         {
             cancellationToken.ThrowIfCancellationRequested();
 
-            progress.Report(new TaskProgress { PercentComplete = 0 });
+            progress.Report(0);
             
             return Task.Run(() => Kernel.ReloadLogger());
         }

+ 27 - 15
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<IKernel>
     {
+        /// <summary>
+        /// The _app host
+        /// </summary>
+        private readonly IApplicationHost _appHost;
+
+        /// <summary>
+        /// Initializes a new instance of the <see cref="SystemUpdateTask" /> class.
+        /// </summary>
+        /// <param name="appHost">The app host.</param>
+        [ImportingConstructor]
+        public SystemUpdateTask([Import("appHost")] IApplicationHost appHost)
+        {
+            _appHost = appHost;
+        }
+
         /// <summary>
         /// Creates the triggers that define when the task will run
         /// </summary>
@@ -37,26 +49,26 @@ namespace MediaBrowser.Common.ScheduledTasks.Tasks
         /// <param name="cancellationToken">The cancellation token.</param>
         /// <param name="progress">The progress.</param>
         /// <returns>Task.</returns>
-        protected override async Task ExecuteInternal(CancellationToken cancellationToken, IProgress<TaskProgress> progress)
+        protected override async Task ExecuteInternal(CancellationToken cancellationToken, IProgress<double> progress)
         {
-            if (!ApplicationDeployment.IsNetworkDeployed) return;
+            if (!_appHost.CanSelfUpdate) return;
 
-            EventHandler<TaskProgress> innerProgressHandler = (sender, e) => progress.Report(new TaskProgress { PercentComplete = e.PercentComplete * .1 });
+            EventHandler<double> innerProgressHandler = (sender, e) => progress.Report(e * .1);
 
             // Create a progress object for the update check
-            var innerProgress = new Progress<TaskProgress>();
+            var innerProgress = new Progress<double>();
             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<TaskProgress>();
+                innerProgress = new Progress<double>();
                 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);
         }
 
         /// <summary>

+ 1 - 1
MediaBrowser.Controller/Entities/CollectionFolder.cs

@@ -56,7 +56,7 @@ namespace MediaBrowser.Controller.Entities
         /// <param name="cancellationToken">The cancellation token.</param>
         /// <param name="recursive">if set to <c>true</c> [recursive].</param>
         /// <returns>Task.</returns>
-        protected override Task ValidateChildrenInternal(IProgress<TaskProgress> progress, CancellationToken cancellationToken, bool? recursive = null)
+        protected override Task ValidateChildrenInternal(IProgress<double> progress, CancellationToken cancellationToken, bool? recursive = null)
         {
             //we don't directly validate our children
             //but we do need to clear out the index cache...

+ 9 - 9
MediaBrowser.Controller/Entities/Folder.cs

@@ -612,7 +612,7 @@ namespace MediaBrowser.Controller.Entities
         /// <param name="cancellationToken">The cancellation token.</param>
         /// <param name="recursive">if set to <c>true</c> [recursive].</param>
         /// <returns>Task.</returns>
-        public async Task ValidateChildren(IProgress<TaskProgress> progress, CancellationToken cancellationToken, bool? recursive = null)
+        public async Task ValidateChildren(IProgress<double> progress, CancellationToken cancellationToken, bool? recursive = null)
         {
             cancellationToken.ThrowIfCancellationRequested();
 
@@ -664,7 +664,7 @@ namespace MediaBrowser.Controller.Entities
         /// <param name="cancellationToken">The cancellation token.</param>
         /// <param name="recursive">if set to <c>true</c> [recursive].</param>
         /// <returns>Task.</returns>
-        protected async virtual Task ValidateChildrenInternal(IProgress<TaskProgress> progress, CancellationToken cancellationToken, bool? recursive = null)
+        protected async virtual Task ValidateChildrenInternal(IProgress<double> 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);
         }
 
         /// <summary>
@@ -789,7 +789,7 @@ namespace MediaBrowser.Controller.Entities
         /// <param name="cancellationToken">The cancellation token.</param>
         /// <param name="recursive">if set to <c>true</c> [recursive].</param>
         /// <returns>Task.</returns>
-        private Task RefreshChildren(IEnumerable<Tuple<BaseItem, bool>> children, IProgress<TaskProgress> progress, CancellationToken cancellationToken, bool? recursive)
+        private Task RefreshChildren(IEnumerable<Tuple<BaseItem, bool>> children, IProgress<double> progress, CancellationToken cancellationToken, bool? recursive)
         {
             var numComplete = 0;
 
@@ -824,7 +824,7 @@ namespace MediaBrowser.Controller.Entities
                 {
                     cancellationToken.ThrowIfCancellationRequested();
 
-                    await ((Folder)child).ValidateChildren(new Progress<TaskProgress> { }, cancellationToken, recursive: recursive).ConfigureAwait(false);
+                    await ((Folder)child).ValidateChildren(new Progress<double> { }, 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<TaskProgress> { };
+            var progress = new Progress<double> { };
 
             await ValidateChildren(progress, CancellationToken.None).ConfigureAwait(false);
         }

+ 3 - 3
MediaBrowser.Controller/Entities/User.cs

@@ -205,7 +205,7 @@ namespace MediaBrowser.Controller.Entities
         /// <param name="cancellationToken">The cancellation token.</param>
         /// <param name="progress">The progress.</param>
         /// <returns>Task.</returns>
-        public async Task ValidateMediaLibrary(IProgress<TaskProgress> progress, CancellationToken cancellationToken)
+        public async Task ValidateMediaLibrary(IProgress<double> 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
         /// <param name="cancellationToken">The cancellation token.</param>
         /// <param name="progress">The progress.</param>
         /// <returns>Task.</returns>
-        public async Task ValidateCollectionFolders(IProgress<TaskProgress> progress, CancellationToken cancellationToken)
+        public async Task ValidateCollectionFolders(IProgress<double> 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<TaskProgress> { }, CancellationToken.None));
+            Task.Run(() => ValidateMediaLibrary(new Progress<double> { }, CancellationToken.None));
 
             return RefreshMetadata(CancellationToken.None, forceSave: true, forceRefresh: true);
         }

+ 1 - 1
MediaBrowser.Common/Net/NetworkShares.cs → 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
 {
     /// <summary>
     /// Type of share

+ 7 - 7
MediaBrowser.Controller/Library/LibraryManager.cs

@@ -369,7 +369,7 @@ namespace MediaBrowser.Controller.Library
         /// <param name="cancellationToken">The cancellation token.</param>
         /// <param name="progress">The progress.</param>
         /// <returns>Task.</returns>
-        internal async Task ValidatePeople(CancellationToken cancellationToken, IProgress<TaskProgress> progress)
+        internal async Task ValidatePeople(CancellationToken cancellationToken, IProgress<double> 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
         /// <param name="progress">The progress.</param>
         /// <param name="cancellationToken">The cancellation token.</param>
         /// <returns>Task.</returns>
-        internal async Task ValidateMediaLibrary(IProgress<TaskProgress> progress, CancellationToken cancellationToken)
+        internal async Task ValidateMediaLibrary(IProgress<double> 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<TaskProgress> { }, cancellationToken, recursive: false);
+            await Kernel.RootFolder.ValidateChildren(new Progress<double> { }, 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<TaskProgress> { }, cancellationToken));
+            var userCollectionFolderTasks = Kernel.Users.AsParallel().Select(user => user.ValidateCollectionFolders(new Progress<double> { }, 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<TaskProgress> { }, cancellationToken).ConfigureAwait(false);
+                await user.ValidateMediaLibrary(new Progress<double> { }, cancellationToken).ConfigureAwait(false);
             }
         }
 

+ 1 - 1
MediaBrowser.Controller/MediaBrowser.Controller.csproj

@@ -67,7 +67,6 @@
     <Reference Include="System.ComponentModel.Composition" />
     <Reference Include="System.Core" />
     <Reference Include="System.Data" />
-    <Reference Include="System.Deployment" />
     <Reference Include="System.Drawing" />
     <Reference Include="System.Net" />
     <Reference Include="System.Runtime.Serialization" />
@@ -106,6 +105,7 @@
     <Compile Include="Entities\Year.cs" />
     <Compile Include="Extensions\XmlExtensions.cs" />
     <Compile Include="IO\FileSystemManager.cs" />
+    <Compile Include="IO\NetworkShares.cs" />
     <Compile Include="Library\ChildrenChangedEventArgs.cs" />
     <Compile Include="Library\DtoBuilder.cs" />
     <Compile Include="Library\Profiler.cs" />

+ 2 - 2
MediaBrowser.Controller/ScheduledTasks/ChapterImagesTask.cs

@@ -31,7 +31,7 @@ namespace MediaBrowser.Controller.ScheduledTasks
         /// <param name="cancellationToken">The cancellation token.</param>
         /// <param name="progress">The progress.</param>
         /// <returns>Task.</returns>
-        protected override Task ExecuteInternal(CancellationToken cancellationToken, IProgress<TaskProgress> progress)
+        protected override Task ExecuteInternal(CancellationToken cancellationToken, IProgress<double> progress)
         {
             var videos = Kernel.RootFolder.RecursiveChildren.OfType<Video>().Where(v => v.Chapters != null).ToList();
 
@@ -59,7 +59,7 @@ namespace MediaBrowser.Controller.ScheduledTasks
                         double percent = numComplete;
                         percent /= videos.Count;
 
-                        progress.Report(new TaskProgress { PercentComplete = 100 * percent });
+                        progress.Report(100 * percent);
                     }
                 }
             }));

+ 2 - 2
MediaBrowser.Controller/ScheduledTasks/ImageCleanupTask.cs

@@ -37,7 +37,7 @@ namespace MediaBrowser.Controller.ScheduledTasks
         /// <param name="cancellationToken">The cancellation token.</param>
         /// <param name="progress">The progress.</param>
         /// <returns>Task.</returns>
-        protected override async Task ExecuteInternal(CancellationToken cancellationToken, IProgress<TaskProgress> progress)
+        protected override async Task ExecuteInternal(CancellationToken cancellationToken, IProgress<double> progress)
         {
             await EnsureChapterImages(cancellationToken).ConfigureAwait(false);
 
@@ -83,7 +83,7 @@ namespace MediaBrowser.Controller.ScheduledTasks
                     double percent = numComplete;
                     percent /= files.Count;
 
-                    progress.Report(new TaskProgress { PercentComplete = 100 * percent });
+                    progress.Report(100 * percent);
                 }
             }));
 

+ 1 - 1
MediaBrowser.Controller/ScheduledTasks/PeopleValidationTask.cs

@@ -34,7 +34,7 @@ namespace MediaBrowser.Controller.ScheduledTasks
         /// <param name="cancellationToken">The cancellation token.</param>
         /// <param name="progress">The progress.</param>
         /// <returns>Task.</returns>
-        protected override Task ExecuteInternal(CancellationToken cancellationToken, IProgress<TaskProgress> progress)
+        protected override Task ExecuteInternal(CancellationToken cancellationToken, IProgress<double> progress)
         {
             return Kernel.LibraryManager.ValidatePeople(cancellationToken, progress);
         }

+ 5 - 5
MediaBrowser.Controller/ScheduledTasks/PluginUpdateTask.cs

@@ -38,13 +38,13 @@ namespace MediaBrowser.Controller.ScheduledTasks
         /// <param name="cancellationToken">The cancellation token.</param>
         /// <param name="progress">The progress.</param>
         /// <returns>Task.</returns>
-        protected override async Task ExecuteInternal(CancellationToken cancellationToken, IProgress<TaskProgress> progress)
+        protected override async Task ExecuteInternal(CancellationToken cancellationToken, IProgress<double> progress)
         {
-            progress.Report(new TaskProgress { Description = "Checking for plugin updates", PercentComplete = 0 });
+            progress.Report(0);
 
             var packagesToInstall = (await Kernel.InstallationManager.GetAvailablePluginUpdates(true, cancellationToken).ConfigureAwait(false)).ToList();
 
-            progress.Report(new TaskProgress { PercentComplete = 10 });
+            progress.Report(10);
 
             var numComplete = 0;
 
@@ -81,7 +81,7 @@ namespace MediaBrowser.Controller.ScheduledTasks
                     double percent = numComplete;
                     percent /= packagesToInstall.Count;
 
-                    progress.Report(new TaskProgress { PercentComplete = (90 * percent) + 10 });
+                    progress.Report((90 * percent) + 10);
                 }
             }));
 
@@ -89,7 +89,7 @@ namespace MediaBrowser.Controller.ScheduledTasks
 
             await Task.WhenAll(tasks).ConfigureAwait(false);
 
-            progress.Report(new TaskProgress { PercentComplete = 100 });
+            progress.Report(100);
         }
 
         /// <summary>

+ 2 - 2
MediaBrowser.Controller/ScheduledTasks/RefreshMediaLibraryTask.cs

@@ -36,11 +36,11 @@ namespace MediaBrowser.Controller.ScheduledTasks
         /// <param name="cancellationToken">The cancellation token.</param>
         /// <param name="progress">The progress.</param>
         /// <returns>Task.</returns>
-        protected override Task ExecuteInternal(CancellationToken cancellationToken, IProgress<TaskProgress> progress)
+        protected override Task ExecuteInternal(CancellationToken cancellationToken, IProgress<double> progress)
         {
             cancellationToken.ThrowIfCancellationRequested();
 
-            progress.Report(new TaskProgress { PercentComplete = 0 });
+            progress.Report(0);
 
             return Kernel.LibraryManager.ValidateMediaLibrary(progress, cancellationToken);
         }

+ 1 - 1
MediaBrowser.Model/MediaBrowser.Model.csproj

@@ -70,6 +70,7 @@
     <Compile Include="Logging\LogSeverity.cs" />
     <Compile Include="MediaInfo\IBlurayExaminer.cs" />
     <Compile Include="Net\HttpException.cs" />
+    <Compile Include="Updates\CheckForUpdateResult.cs" />
     <Compile Include="Updates\InstallationInfo.cs" />
     <Compile Include="Updates\PackageType.cs" />
     <Compile Include="Updates\PackageVersionClass.cs" />
@@ -97,7 +98,6 @@
     <Compile Include="Tasks\TaskCompletionStatus.cs" />
     <Compile Include="Tasks\TaskResult.cs" />
     <Compile Include="Tasks\TaskInfo.cs" />
-    <Compile Include="Tasks\TaskProgress.cs" />
     <Compile Include="Tasks\TaskState.cs" />
     <Compile Include="Tasks\TaskTriggerInfo.cs" />
     <Compile Include="Updates\PackageInfo.cs" />

+ 1 - 1
MediaBrowser.Model/Tasks/TaskInfo.cs

@@ -28,7 +28,7 @@ namespace MediaBrowser.Model.Tasks
         /// </summary>
         /// <value>The progress.</value>
         [ProtoMember(3)]
-        public TaskProgress CurrentProgress { get; set; }
+        public double? CurrentProgressPercentage { get; set; }
 
         /// <summary>
         /// Gets or sets the id.

+ 0 - 22
MediaBrowser.Model/Tasks/TaskProgress.cs

@@ -1,22 +0,0 @@
-using ProtoBuf;
-
-namespace MediaBrowser.Model.Tasks
-{
-    [ProtoContract]
-    public class TaskProgress
-    {
-        /// <summary>
-        /// Gets or sets the description.
-        /// </summary>
-        /// <value>The description.</value>
-        [ProtoMember(1)]
-        public string Description { get; set; }
-
-        /// <summary>
-        /// Gets or sets the percent complete.
-        /// </summary>
-        /// <value>The percent complete.</value>
-        [ProtoMember(2)]
-        public double PercentComplete { get; set; }
-    }
-}

+ 22 - 0
MediaBrowser.Model/Updates/CheckForUpdateResult.cs

@@ -0,0 +1,22 @@
+using System;
+
+namespace MediaBrowser.Model.Updates
+{
+    /// <summary>
+    /// Class CheckForUpdateResult
+    /// </summary>
+    public class CheckForUpdateResult
+    {
+        /// <summary>
+        /// Gets or sets a value indicating whether this instance is update available.
+        /// </summary>
+        /// <value><c>true</c> if this instance is update available; otherwise, <c>false</c>.</value>
+        public bool IsUpdateAvailable { get; set; }
+
+        /// <summary>
+        /// Gets or sets the available version.
+        /// </summary>
+        /// <value>The available version.</value>
+        public Version AvailableVersion { get; set; }
+    }
+}

+ 4 - 4
MediaBrowser.Plugins.Trailers/ScheduledTasks/CurrentTrailerDownloadTask.cs

@@ -39,12 +39,12 @@ namespace MediaBrowser.Plugins.Trailers.ScheduledTasks
         /// <param name="cancellationToken">The cancellation token.</param>
         /// <param name="progress">The progress.</param>
         /// <returns>Task.</returns>
-        protected override async Task ExecuteInternal(CancellationToken cancellationToken, IProgress<TaskProgress> progress)
+        protected override async Task ExecuteInternal(CancellationToken cancellationToken, IProgress<double> progress)
         {
             // Get the list of trailers
             var trailers = await AppleTrailerListingDownloader.GetTrailerList(cancellationToken).ConfigureAwait(false);
 
-            progress.Report(new TaskProgress { PercentComplete = 1 });
+            progress.Report(1);
 
             var trailersToDownload = trailers.Where(t => !IsOldTrailer(t.Video)).ToList();
 
@@ -74,7 +74,7 @@ namespace MediaBrowser.Plugins.Trailers.ScheduledTasks
                     percent /= trailersToDownload.Count;
 
                     // Leave 1% for DeleteOldTrailers
-                    progress.Report(new TaskProgress { PercentComplete = (99 * percent) + 1 });
+                    progress.Report((99 * percent) + 1);
                 }
             }));
 
@@ -90,7 +90,7 @@ namespace MediaBrowser.Plugins.Trailers.ScheduledTasks
                 DeleteOldTrailers();
             }
 
-            progress.Report(new TaskProgress { PercentComplete = 100 });
+            progress.Report(100);
         }
 
         /// <summary>

+ 3 - 3
MediaBrowser.Server.Uninstall/MediaBrowser.Server.Uninstall.csproj

@@ -52,9 +52,9 @@
     <None Include="App.config" />
   </ItemGroup>
   <ItemGroup>
-    <ProjectReference Include="..\MediaBrowser.Common\MediaBrowser.Common.csproj">
-      <Project>{9142eefa-7570-41e1-bfcc-468bb571af2f}</Project>
-      <Name>MediaBrowser.Common</Name>
+    <ProjectReference Include="..\MediaBrowser.ClickOnce\MediaBrowser.ClickOnce.csproj">
+      <Project>{cc96bf3e-0bda-4809-bc4b-bb6d418f4a84}</Project>
+      <Name>MediaBrowser.ClickOnce</Name>
     </ProjectReference>
   </ItemGroup>
   <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />

+ 1 - 1
MediaBrowser.Server.Uninstall/Program.cs

@@ -1,4 +1,4 @@
-using MediaBrowser.Common.Updates;
+using MediaBrowser.ClickOnce;
 using System;
 using System.IO;
 

+ 36 - 20
MediaBrowser.ServerApplication/App.xaml.cs

@@ -1,14 +1,14 @@
-using MediaBrowser.Common.Kernel;
-using MediaBrowser.Common.Updates;
+using MediaBrowser.ClickOnce;
+using MediaBrowser.Common.Kernel;
 using MediaBrowser.Controller;
 using MediaBrowser.IsoMounter;
 using MediaBrowser.Logging.Nlog;
 using MediaBrowser.Model.Logging;
+using MediaBrowser.Model.Updates;
 using MediaBrowser.Server.Uninstall;
 using MediaBrowser.ServerApplication.Implementations;
 using Microsoft.Win32;
 using System;
-using System.Deployment.Application;
 using System.Diagnostics;
 using System.IO;
 using System.Linq;
@@ -71,7 +71,7 @@ namespace MediaBrowser.ServerApplication
         /// Gets or sets the log file path.
         /// </summary>
         /// <value>The log file path.</value>
-        private string LogFilePath { get; set; }
+        public string LogFilePath { get; private set; }
 
         /// <summary>
         /// Initializes a new instance of the <see cref="App" /> class.
@@ -235,24 +235,9 @@ namespace MediaBrowser.ServerApplication
         /// </summary>
         private void ConfigureClickOnceStartup()
         {
-            if (!ApplicationDeployment.IsNetworkDeployed)
-            {
-                return;
-            }
-
             try
             {
-                var clickOnceHelper = new ClickOnceHelper(PublisherName, ProductName, SuiteName);
-
-                if (Kernel.Configuration.RunAtStartup)
-                {
-                    clickOnceHelper.UpdateUninstallParameters(UninstallerFileName);
-                    clickOnceHelper.AddShortcutToStartup();
-                }
-                else
-                {
-                    clickOnceHelper.RemoveShortcutFromStartup();
-                }
+                ClickOnceHelper.ConfigureClickOnceStartupIfInstalled(PublisherName, ProductName, SuiteName, Kernel.Configuration.RunAtStartup, UninstallerFileName);
 
                 LastRunAtStartupValue = Kernel.Configuration.RunAtStartup;
             }
@@ -469,5 +454,36 @@ namespace MediaBrowser.ServerApplication
             RenderOptions.SetBitmapScalingMode(bitmap, BitmapScalingMode.Fant);
             return bitmap;
         }
+
+        /// <summary>
+        /// Gets or sets a value indicating whether this instance can self update.
+        /// </summary>
+        /// <value><c>true</c> if this instance can self update; otherwise, <c>false</c>.</value>
+        public bool CanSelfUpdate
+        {
+            get { return ClickOnceHelper.IsNetworkDeployed; }
+        }
+
+        /// <summary>
+        /// Checks for update.
+        /// </summary>
+        /// <param name="cancellationToken">The cancellation token.</param>
+        /// <param name="progress">The progress.</param>
+        /// <returns>Task{CheckForUpdateResult}.</returns>
+        public Task<CheckForUpdateResult> CheckForApplicationUpdate(CancellationToken cancellationToken, IProgress<double> progress)
+        {
+            return new ApplicationUpdateCheck().CheckForApplicationUpdate(cancellationToken, progress);
+        }
+
+        /// <summary>
+        /// Updates the application.
+        /// </summary>
+        /// <param name="cancellationToken">The cancellation token.</param>
+        /// <param name="progress">The progress.</param>
+        /// <returns>Task.</returns>
+        public Task UpdateApplication(CancellationToken cancellationToken, IProgress<double> progress)
+        {
+            return new ApplicationUpdater().UpdateApplication(cancellationToken, progress);
+        }
     }
 }

+ 1 - 1
MediaBrowser.ServerApplication/LibraryExplorer.xaml.cs

@@ -41,7 +41,7 @@ namespace MediaBrowser.ServerApplication
             _logger = logger;
 
             InitializeComponent();
-            lblVersion.Content = "Version: " + Kernel.Instance.DisplayVersion;
+            lblVersion.Content = "Version: " + Kernel.Instance.ApplicationVersion;
             foreach (var user in Kernel.Instance.Users)
                 ddlProfile.Items.Add(user);
             ddlProfile.Items.Insert(0,new User {Name = "Physical"});

+ 4 - 1
MediaBrowser.ServerApplication/MediaBrowser.ServerApplication.csproj

@@ -138,7 +138,6 @@
     <Reference Include="System.Data.SQLite.Linq">
       <HintPath>..\packages\System.Data.SQLite.1.0.84.0\lib\net45\System.Data.SQLite.Linq.dll</HintPath>
     </Reference>
-    <Reference Include="System.Deployment" />
     <Reference Include="System.Drawing" />
     <Reference Include="System.Runtime.Remoting" />
     <Reference Include="System.Web.Extensions" />
@@ -240,6 +239,10 @@
       <Project>{07b509c0-0c28-4f3f-8963-5263281f7e3d}</Project>
       <Name>BDInfo</Name>
     </ProjectReference>
+    <ProjectReference Include="..\MediaBrowser.ClickOnce\MediaBrowser.ClickOnce.csproj">
+      <Project>{cc96bf3e-0bda-4809-bc4b-bb6d418f4a84}</Project>
+      <Name>MediaBrowser.ClickOnce</Name>
+    </ProjectReference>
     <ProjectReference Include="..\MediaBrowser.Common\MediaBrowser.Common.csproj">
       <Project>{9142eefa-7570-41e1-bfcc-468bb571af2f}</Project>
       <Name>MediaBrowser.Common</Name>

+ 3 - 3
MediaBrowser.UI.Uninstall/MediaBrowser.UI.Uninstall.csproj

@@ -52,9 +52,9 @@
     <None Include="App.config" />
   </ItemGroup>
   <ItemGroup>
-    <ProjectReference Include="..\MediaBrowser.Common\MediaBrowser.Common.csproj">
-      <Project>{9142eefa-7570-41e1-bfcc-468bb571af2f}</Project>
-      <Name>MediaBrowser.Common</Name>
+    <ProjectReference Include="..\MediaBrowser.ClickOnce\MediaBrowser.ClickOnce.csproj">
+      <Project>{cc96bf3e-0bda-4809-bc4b-bb6d418f4a84}</Project>
+      <Name>MediaBrowser.ClickOnce</Name>
     </ProjectReference>
   </ItemGroup>
   <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />

+ 1 - 1
MediaBrowser.UI.Uninstall/Program.cs

@@ -1,4 +1,4 @@
-using MediaBrowser.Common.Updates;
+using MediaBrowser.ClickOnce;
 using System;
 using System.IO;
 

+ 12 - 0
MediaBrowser.UI.sln

@@ -23,6 +23,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MediaBrowser.UI.Controls",
 EndProject
 Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MediaBrowser.Logging.NLog", "MediaBrowser.Logging.NLog\MediaBrowser.Logging.NLog.csproj", "{67310740-0EC4-4DC2-9921-33DF38B20167}"
 EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MediaBrowser.ClickOnce", "MediaBrowser.ClickOnce\MediaBrowser.ClickOnce.csproj", "{CC96BF3E-0BDA-4809-BC4B-BB6D418F4A84}"
+EndProject
 Global
 	GlobalSection(SolutionConfigurationPlatforms) = preSolution
 		Debug|Any CPU = Debug|Any CPU
@@ -155,6 +157,16 @@ Global
 		{67310740-0EC4-4DC2-9921-33DF38B20167}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU
 		{67310740-0EC4-4DC2-9921-33DF38B20167}.Release|Mixed Platforms.Build.0 = Release|Any CPU
 		{67310740-0EC4-4DC2-9921-33DF38B20167}.Release|x86.ActiveCfg = Release|Any CPU
+		{CC96BF3E-0BDA-4809-BC4B-BB6D418F4A84}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{CC96BF3E-0BDA-4809-BC4B-BB6D418F4A84}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{CC96BF3E-0BDA-4809-BC4B-BB6D418F4A84}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU
+		{CC96BF3E-0BDA-4809-BC4B-BB6D418F4A84}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU
+		{CC96BF3E-0BDA-4809-BC4B-BB6D418F4A84}.Debug|x86.ActiveCfg = Debug|Any CPU
+		{CC96BF3E-0BDA-4809-BC4B-BB6D418F4A84}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{CC96BF3E-0BDA-4809-BC4B-BB6D418F4A84}.Release|Any CPU.Build.0 = Release|Any CPU
+		{CC96BF3E-0BDA-4809-BC4B-BB6D418F4A84}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU
+		{CC96BF3E-0BDA-4809-BC4B-BB6D418F4A84}.Release|Mixed Platforms.Build.0 = Release|Any CPU
+		{CC96BF3E-0BDA-4809-BC4B-BB6D418F4A84}.Release|x86.ActiveCfg = Release|Any CPU
 	EndGlobalSection
 	GlobalSection(SolutionProperties) = preSolution
 		HideSolutionNode = FALSE

+ 39 - 23
MediaBrowser.UI/App.xaml.cs

@@ -1,33 +1,33 @@
-using System.Deployment.Application;
-using System.Net.Cache;
-using System.Windows.Media;
-using MediaBrowser.ApiInteraction;
+using MediaBrowser.ApiInteraction;
+using MediaBrowser.ClickOnce;
 using MediaBrowser.Common.Extensions;
 using MediaBrowser.Common.IO;
 using MediaBrowser.Common.Kernel;
-using MediaBrowser.Common.Updates;
 using MediaBrowser.IsoMounter;
 using MediaBrowser.Logging.Nlog;
 using MediaBrowser.Model.Configuration;
 using MediaBrowser.Model.Dto;
 using MediaBrowser.Model.Logging;
 using MediaBrowser.Model.Net;
+using MediaBrowser.Model.Updates;
 using MediaBrowser.Model.Weather;
 using MediaBrowser.UI.Controller;
 using MediaBrowser.UI.Controls;
 using MediaBrowser.UI.Pages;
 using MediaBrowser.UI.Uninstall;
+using Microsoft.Win32;
 using System;
 using System.Collections.Generic;
 using System.ComponentModel;
 using System.IO;
 using System.Linq;
+using System.Net.Cache;
 using System.Threading;
 using System.Threading.Tasks;
 using System.Windows;
 using System.Windows.Controls;
+using System.Windows.Media;
 using System.Windows.Media.Imaging;
-using Microsoft.Win32;
 
 namespace MediaBrowser.UI
 {
@@ -74,7 +74,7 @@ namespace MediaBrowser.UI
         /// Gets or sets the log file path.
         /// </summary>
         /// <value>The log file path.</value>
-        private string LogFilePath { get; set; }
+        public string LogFilePath { get; private set; }
 
         /// <summary>
         /// Occurs when [property changed].
@@ -916,24 +916,9 @@ namespace MediaBrowser.UI
         /// </summary>
         private void ConfigureClickOnceStartup()
         {
-            if (!ApplicationDeployment.IsNetworkDeployed)
-            {
-                return;
-            }
-
             try
             {
-                var clickOnceHelper = new ClickOnceHelper(PublisherName, ProductName, SuiteName);
-
-                if (Kernel.Configuration.RunAtStartup)
-                {
-                    clickOnceHelper.UpdateUninstallParameters(UninstallerFileName);
-                    clickOnceHelper.AddShortcutToStartup();
-                }
-                else
-                {
-                    clickOnceHelper.RemoveShortcutFromStartup();
-                }
+                ClickOnceHelper.ConfigureClickOnceStartupIfInstalled(PublisherName, ProductName, SuiteName, Kernel.Configuration.RunAtStartup, UninstallerFileName);
 
                 LastRunAtStartupValue = Kernel.Configuration.RunAtStartup;
             }
@@ -1004,5 +989,36 @@ namespace MediaBrowser.UI
             RenderOptions.SetBitmapScalingMode(bitmap, BitmapScalingMode.Fant);
             return bitmap;
         }
+
+        /// <summary>
+        /// Gets or sets a value indicating whether this instance can self update.
+        /// </summary>
+        /// <value><c>true</c> if this instance can self update; otherwise, <c>false</c>.</value>
+        public bool CanSelfUpdate
+        {
+            get { return ClickOnceHelper.IsNetworkDeployed; }
+        }
+
+        /// <summary>
+        /// Checks for update.
+        /// </summary>
+        /// <param name="cancellationToken">The cancellation token.</param>
+        /// <param name="progress">The progress.</param>
+        /// <returns>Task{CheckForUpdateResult}.</returns>
+        public Task<CheckForUpdateResult> CheckForApplicationUpdate(CancellationToken cancellationToken, IProgress<double> progress)
+        {
+            return new ApplicationUpdateCheck().CheckForApplicationUpdate(cancellationToken, progress);
+        }
+
+        /// <summary>
+        /// Updates the application.
+        /// </summary>
+        /// <param name="cancellationToken">The cancellation token.</param>
+        /// <param name="progress">The progress.</param>
+        /// <returns>Task.</returns>
+        public Task UpdateApplication(CancellationToken cancellationToken, IProgress<double> progress)
+        {
+            return new ApplicationUpdater().UpdateApplication(cancellationToken, progress);
+        }
     }
 }

+ 26 - 0
MediaBrowser.UI/Extensions/Extensions.cs

@@ -0,0 +1,26 @@
+using System;
+using System.Windows.Threading;
+
+namespace MediaBrowser.UI.Extensions
+{
+    public static class Extensions
+    {
+        /// <summary>
+        /// Invokes an action after a specified delay
+        /// </summary>
+        /// <param name="dispatcher">The dispatcher.</param>
+        /// <param name="action">The action.</param>
+        /// <param name="delayMs">The delay ms.</param>
+        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();
+        }
+    }
+}

+ 1 - 0
MediaBrowser.UI/MainWindow.xaml.cs

@@ -11,6 +11,7 @@ using System.Threading.Tasks;
 using System.Windows;
 using System.Windows.Controls;
 using System.Windows.Input;
+using MediaBrowser.UI.Extensions;
 
 namespace MediaBrowser.UI
 {

+ 5 - 1
MediaBrowser.UI/MediaBrowser.UI.csproj

@@ -116,7 +116,6 @@
     <Reference Include="System" />
     <Reference Include="System.ComponentModel.Composition" />
     <Reference Include="System.Data" />
-    <Reference Include="System.Deployment" />
     <Reference Include="System.Drawing" />
     <Reference Include="System.Net" />
     <Reference Include="System.Net.Http" />
@@ -153,6 +152,7 @@
     <Compile Include="Controls\NotificationMessage.xaml.cs">
       <DependentUpon>NotificationMessage.xaml</DependentUpon>
     </Compile>
+    <Compile Include="Extensions\Extensions.cs" />
     <Compile Include="HiddenWindow.xaml.cs">
       <DependentUpon>HiddenWindow.xaml</DependentUpon>
     </Compile>
@@ -300,6 +300,10 @@
       <Project>{921c0f64-fda7-4e9f-9e73-0cb0eedb2422}</Project>
       <Name>MediaBrowser.ApiInteraction</Name>
     </ProjectReference>
+    <ProjectReference Include="..\MediaBrowser.ClickOnce\MediaBrowser.ClickOnce.csproj">
+      <Project>{cc96bf3e-0bda-4809-bc4b-bb6d418f4a84}</Project>
+      <Name>MediaBrowser.ClickOnce</Name>
+    </ProjectReference>
     <ProjectReference Include="..\MediaBrowser.Common\MediaBrowser.Common.csproj">
       <Project>{9142eefa-7570-41e1-bfcc-468bb571af2f}</Project>
       <Name>MediaBrowser.Common</Name>

+ 2 - 2
MediaBrowser.WebDashboard/Html/scripts/DashboardPage.js

@@ -252,8 +252,8 @@
             html += task.Name;
 
             if (task.State == "Running") {
-                var progress = task.CurrentProgress || { PercentComplete: 0 };
-                html += '<span style="color:#267F00;margin-right:5px;font-weight:bold;"> - ' + Math.round(progress.PercentComplete) + '%</span>';
+                var progress = Math.round(task.CurrentProgressPercentage || 0);
+                html += '<span style="color:#267F00;margin-right:5px;font-weight:bold;"> - ' + progress + '%</span>';
 
                 html += '<button type="button" data-icon="stop" data-iconpos="notext" data-inline="true" data-theme="b" data-mini="true" onclick="DashboardPage.stopTask(\'' + task.Id + '\');">Stop</button>';
             }

+ 1 - 2
MediaBrowser.WebDashboard/Html/scripts/ScheduledTasksPage.js

@@ -119,8 +119,7 @@
             }
             else if (task.State == "Running") {
 
-                var progress = task.CurrentProgress || { PercentComplete: 0 };
-                progress = Math.round(progress.PercentComplete);
+                var progress = Math.round(task.CurrentProgressPercentage || 0);
                 
                 html += '<p><progress max="100" value="' + progress + '" title="' + progress + '%">';
                 html += '' + progress + '%';

+ 16 - 0
MediaBrowser.sln

@@ -51,6 +51,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MediaBrowser.Server.WorldWe
 EndProject
 Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MediaBrowser.Logging.NLog", "MediaBrowser.Logging.NLog\MediaBrowser.Logging.NLog.csproj", "{67310740-0EC4-4DC2-9921-33DF38B20167}"
 EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MediaBrowser.ClickOnce", "MediaBrowser.ClickOnce\MediaBrowser.ClickOnce.csproj", "{CC96BF3E-0BDA-4809-BC4B-BB6D418F4A84}"
+EndProject
 Global
 	GlobalSection(SolutionConfigurationPlatforms) = preSolution
 		Debug|Any CPU = Debug|Any CPU
@@ -335,6 +337,20 @@ Global
 		{67310740-0EC4-4DC2-9921-33DF38B20167}.Release|Win32.ActiveCfg = Release|Any CPU
 		{67310740-0EC4-4DC2-9921-33DF38B20167}.Release|x64.ActiveCfg = Release|Any CPU
 		{67310740-0EC4-4DC2-9921-33DF38B20167}.Release|x86.ActiveCfg = Release|Any CPU
+		{CC96BF3E-0BDA-4809-BC4B-BB6D418F4A84}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{CC96BF3E-0BDA-4809-BC4B-BB6D418F4A84}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{CC96BF3E-0BDA-4809-BC4B-BB6D418F4A84}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU
+		{CC96BF3E-0BDA-4809-BC4B-BB6D418F4A84}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU
+		{CC96BF3E-0BDA-4809-BC4B-BB6D418F4A84}.Debug|Win32.ActiveCfg = Debug|Any CPU
+		{CC96BF3E-0BDA-4809-BC4B-BB6D418F4A84}.Debug|x64.ActiveCfg = Debug|Any CPU
+		{CC96BF3E-0BDA-4809-BC4B-BB6D418F4A84}.Debug|x86.ActiveCfg = Debug|Any CPU
+		{CC96BF3E-0BDA-4809-BC4B-BB6D418F4A84}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{CC96BF3E-0BDA-4809-BC4B-BB6D418F4A84}.Release|Any CPU.Build.0 = Release|Any CPU
+		{CC96BF3E-0BDA-4809-BC4B-BB6D418F4A84}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU
+		{CC96BF3E-0BDA-4809-BC4B-BB6D418F4A84}.Release|Mixed Platforms.Build.0 = Release|Any CPU
+		{CC96BF3E-0BDA-4809-BC4B-BB6D418F4A84}.Release|Win32.ActiveCfg = Release|Any CPU
+		{CC96BF3E-0BDA-4809-BC4B-BB6D418F4A84}.Release|x64.ActiveCfg = Release|Any CPU
+		{CC96BF3E-0BDA-4809-BC4B-BB6D418F4A84}.Release|x86.ActiveCfg = Release|Any CPU
 	EndGlobalSection
 	GlobalSection(SolutionProperties) = preSolution
 		HideSolutionNode = FALSE