From d00178d8f0002638d47174c0bd73ebcf1ac5f6fd Mon Sep 17 00:00:00 2001 From: Luke Pulverenti Date: Fri, 13 Dec 2013 10:48:35 -0500 Subject: [PATCH] support progress bar while splash window is up --- .../BaseApplicationHost.cs | 26 +++---- MediaBrowser.Common/IApplicationHost.cs | 3 +- MediaBrowser.ServerApplication/App.xaml.cs | 10 +-- .../ApplicationHost.cs | 37 +++++----- .../FFMpeg/FFMpegDownloader.cs | 72 ++++++++++++++----- .../Splash/SplashWindow.xaml | 13 ++-- .../Splash/SplashWindow.xaml.cs | 37 ++++++---- 7 files changed, 126 insertions(+), 72 deletions(-) diff --git a/MediaBrowser.Common.Implementations/BaseApplicationHost.cs b/MediaBrowser.Common.Implementations/BaseApplicationHost.cs index 373ca30e80..929745a944 100644 --- a/MediaBrowser.Common.Implementations/BaseApplicationHost.cs +++ b/MediaBrowser.Common.Implementations/BaseApplicationHost.cs @@ -9,6 +9,7 @@ using MediaBrowser.Common.Implementations.Updates; using MediaBrowser.Common.IO; using MediaBrowser.Common.Net; using MediaBrowser.Common.Plugins; +using MediaBrowser.Common.Progress; using MediaBrowser.Common.ScheduledTasks; using MediaBrowser.Common.Security; using MediaBrowser.Common.Updates; @@ -180,7 +181,7 @@ namespace MediaBrowser.Common.Implementations /// Inits this instance. /// /// Task. - public virtual async Task Init() + public virtual async Task Init(IProgress progress) { try { @@ -191,38 +192,39 @@ namespace MediaBrowser.Common.Implementations { // Failing under mono } + progress.Report(1); JsonSerializer = CreateJsonSerializer(); IsFirstRun = !ConfigurationManager.CommonConfiguration.IsStartupWizardCompleted; + progress.Report(2); Logger = LogManager.GetLogger("App"); LogManager.LogSeverity = ConfigurationManager.CommonConfiguration.EnableDebugLevelLogging ? LogSeverity.Debug : LogSeverity.Info; - - OnLoggerLoaded(); + progress.Report(3); DiscoverTypes(); + progress.Report(14); Logger.Info("Version {0} initializing", ApplicationVersion); SetHttpLimit(); + progress.Report(15); + + var innerProgress = new ActionableProgress(); + innerProgress.RegisterAction(p => progress.Report((.8 * p) + 15)); - await RegisterResources().ConfigureAwait(false); + await RegisterResources(innerProgress).ConfigureAwait(false); FindParts(); + progress.Report(95); await InstallIsoMounters(CancellationToken.None).ConfigureAwait(false); - } - - /// - /// Called when [logger loaded]. - /// - protected virtual void OnLoggerLoaded() - { + progress.Report(100); } protected virtual IJsonSerializer CreateJsonSerializer() @@ -348,7 +350,7 @@ namespace MediaBrowser.Common.Implementations /// Registers resources that classes will depend on /// /// Task. - protected virtual Task RegisterResources() + protected virtual Task RegisterResources(IProgress progress) { return Task.Run(() => { diff --git a/MediaBrowser.Common/IApplicationHost.cs b/MediaBrowser.Common/IApplicationHost.cs index 56b86a3c11..1c7ffe4240 100644 --- a/MediaBrowser.Common/IApplicationHost.cs +++ b/MediaBrowser.Common/IApplicationHost.cs @@ -129,8 +129,9 @@ namespace MediaBrowser.Common /// /// Inits this instance. /// + /// The progress. /// Task. - Task Init(); + Task Init(IProgress progress); /// /// Creates the instance. diff --git a/MediaBrowser.ServerApplication/App.xaml.cs b/MediaBrowser.ServerApplication/App.xaml.cs index 9b978ca2df..50bf02debe 100644 --- a/MediaBrowser.ServerApplication/App.xaml.cs +++ b/MediaBrowser.ServerApplication/App.xaml.cs @@ -72,12 +72,14 @@ namespace MediaBrowser.ServerApplication { try { + var initProgress = new Progress(); + if (!IsRunningAsService) { - ShowSplashWindow(); + ShowSplashWindow(initProgress); } - await _appHost.Init(); + await _appHost.Init(initProgress); var task = _appHost.RunStartupTasks(); @@ -131,9 +133,9 @@ namespace MediaBrowser.ServerApplication } private SplashWindow _splashWindow; - private void ShowSplashWindow() + private void ShowSplashWindow(Progress progress) { - var win = new SplashWindow(_appHost.ApplicationVersion); + var win = new SplashWindow(_appHost.ApplicationVersion, progress); win.Show(); _splashWindow = win; diff --git a/MediaBrowser.ServerApplication/ApplicationHost.cs b/MediaBrowser.ServerApplication/ApplicationHost.cs index 46a7430b02..d4b96b6b86 100644 --- a/MediaBrowser.ServerApplication/ApplicationHost.cs +++ b/MediaBrowser.ServerApplication/ApplicationHost.cs @@ -8,6 +8,7 @@ using MediaBrowser.Common.Implementations.ScheduledTasks; using MediaBrowser.Common.IO; using MediaBrowser.Common.MediaInfo; using MediaBrowser.Common.Net; +using MediaBrowser.Common.Progress; using MediaBrowser.Controller; using MediaBrowser.Controller.Configuration; using MediaBrowser.Controller.Drawing; @@ -170,8 +171,6 @@ namespace MediaBrowser.ServerApplication private IItemRepository ItemRepository { get; set; } private INotificationsRepository NotificationsRepository { get; set; } - private Task _httpServerCreationTask; - /// /// Initializes a new instance of the class. /// @@ -215,25 +214,15 @@ namespace MediaBrowser.ServerApplication }); } - /// - /// Called when [logger loaded]. - /// - protected override void OnLoggerLoaded() - { - base.OnLoggerLoaded(); - - _httpServerCreationTask = Task.Run(() => ServerFactory.CreateServer(this, LogManager, "Media Browser", "mediabrowser", "dashboard/index.html")); - } - /// /// Registers resources that classes will depend on /// /// Task. - protected override async Task RegisterResources() + protected override async Task RegisterResources(IProgress progress) { ServerKernel = new Kernel(); - await base.RegisterResources().ConfigureAwait(false); + await base.RegisterResources(progress).ConfigureAwait(false); RegisterSingleInstance(new HttpResultFactory(LogManager, FileSystemManager)); @@ -247,8 +236,6 @@ namespace MediaBrowser.ServerApplication RegisterSingleInstance(() => new BdInfoExaminer()); - var mediaEncoderTask = RegisterMediaEncoder(); - UserDataManager = new UserDataManager(LogManager); RegisterSingleInstance(UserDataManager); @@ -278,8 +265,9 @@ namespace MediaBrowser.ServerApplication SessionManager = new SessionManager(UserDataManager, ServerConfigurationManager, Logger, UserRepository, LibraryManager); RegisterSingleInstance(SessionManager); - HttpServer = await _httpServerCreationTask.ConfigureAwait(false); + HttpServer = ServerFactory.CreateServer(this, LogManager, "Media Browser", "mediabrowser", "dashboard/index.html"); RegisterSingleInstance(HttpServer, false); + progress.Report(10); ServerManager = new ServerManager(this, JsonSerializer, Logger, ServerConfigurationManager); RegisterSingleInstance(ServerManager); @@ -295,14 +283,23 @@ namespace MediaBrowser.ServerApplication LiveTvManager = new LiveTvManager(ApplicationPaths, FileSystemManager, Logger, ItemRepository, ImageProcessor, UserManager, LocalizationManager, UserDataManager, DtoService); RegisterSingleInstance(LiveTvManager); + progress.Report(15); + + var innerProgress = new ActionableProgress(); + innerProgress.RegisterAction(p => progress.Report((.75 * p) + 15)); + + await RegisterMediaEncoder(innerProgress).ConfigureAwait(false); + progress.Report(90); var displayPreferencesTask = Task.Run(async () => await ConfigureDisplayPreferencesRepositories().ConfigureAwait(false)); var itemsTask = Task.Run(async () => await ConfigureItemRepositories().ConfigureAwait(false)); var userdataTask = Task.Run(async () => await ConfigureUserDataRepositories().ConfigureAwait(false)); await ConfigureNotificationsRepository().ConfigureAwait(false); + progress.Report(92); - await Task.WhenAll(itemsTask, displayPreferencesTask, userdataTask, mediaEncoderTask).ConfigureAwait(false); + await Task.WhenAll(itemsTask, displayPreferencesTask, userdataTask).ConfigureAwait(false); + progress.Report(100); SetKernelProperties(); } @@ -321,9 +318,9 @@ namespace MediaBrowser.ServerApplication /// Registers the media encoder. /// /// Task. - private async Task RegisterMediaEncoder() + private async Task RegisterMediaEncoder(IProgress progress) { - var info = await new FFMpegDownloader(Logger, ApplicationPaths, HttpClient, ZipClient, FileSystemManager).GetFFMpegInfo().ConfigureAwait(false); + var info = await new FFMpegDownloader(Logger, ApplicationPaths, HttpClient, ZipClient, FileSystemManager).GetFFMpegInfo(progress).ConfigureAwait(false); MediaEncoder = new MediaEncoder(LogManager.GetLogger("MediaEncoder"), ApplicationPaths, JsonSerializer, info.Path, info.ProbePath, info.Version, FileSystemManager); RegisterSingleInstance(MediaEncoder); diff --git a/MediaBrowser.ServerApplication/FFMpeg/FFMpegDownloader.cs b/MediaBrowser.ServerApplication/FFMpeg/FFMpegDownloader.cs index 8189e84d09..d257ff3624 100644 --- a/MediaBrowser.ServerApplication/FFMpeg/FFMpegDownloader.cs +++ b/MediaBrowser.ServerApplication/FFMpeg/FFMpegDownloader.cs @@ -1,6 +1,7 @@ using MediaBrowser.Common.Configuration; using MediaBrowser.Common.IO; using MediaBrowser.Common.Net; +using MediaBrowser.Common.Progress; using MediaBrowser.Model.IO; using MediaBrowser.Model.Logging; using MediaBrowser.Model.Net; @@ -36,7 +37,7 @@ namespace MediaBrowser.ServerApplication.FFMpeg _fileSystem = fileSystem; } - public async Task GetFFMpegInfo() + public async Task GetFFMpegInfo(IProgress progress) { var versionedDirectoryPath = Path.Combine(GetMediaToolsPath(true), FFMpegDownloadInfo.Version); @@ -51,25 +52,64 @@ namespace MediaBrowser.ServerApplication.FFMpeg var tasks = new List(); + double ffmpegPercent = 0; + double fontPercent = 0; + var syncLock = new object(); + if (!File.Exists(info.ProbePath) || !File.Exists(info.Path)) { - tasks.Add(DownloadFFMpeg(info)); + var ffmpegProgress = new ActionableProgress(); + ffmpegProgress.RegisterAction(p => + { + ffmpegPercent = p; + + lock (syncLock) + { + progress.Report((ffmpegPercent / 2) + (fontPercent / 2)); + } + }); + + tasks.Add(DownloadFFMpeg(info, ffmpegProgress)); + } + else + { + ffmpegPercent = 100; + progress.Report(50); } - tasks.Add(DownloadFonts(versionedDirectoryPath)); + var fontProgress = new ActionableProgress(); + fontProgress.RegisterAction(p => + { + fontPercent = p; + + lock (syncLock) + { + progress.Report((ffmpegPercent / 2) + (fontPercent / 2)); + } + }); + + tasks.Add(DownloadFonts(versionedDirectoryPath, fontProgress)); await Task.WhenAll(tasks).ConfigureAwait(false); return info; } - private async Task DownloadFFMpeg(FFMpegInfo info) + private async Task DownloadFFMpeg(FFMpegInfo info, IProgress progress) { foreach (var url in FFMpegDownloadInfo.FfMpegUrls) { + progress.Report(0); + try { - var tempFile = await DownloadFFMpeg(info, url).ConfigureAwait(false); + var tempFile = await _httpClient.GetTempFile(new HttpRequestOptions + { + Url = url, + CancellationToken = CancellationToken.None, + Progress = progress + + }).ConfigureAwait(false); ExtractFFMpeg(tempFile, Path.GetDirectoryName(info.Path)); return; @@ -83,16 +123,6 @@ namespace MediaBrowser.ServerApplication.FFMpeg throw new ApplicationException("Unable to download required components. Please try again later."); } - private Task DownloadFFMpeg(FFMpegInfo info, string url) - { - return _httpClient.GetTempFile(new HttpRequestOptions - { - Url = url, - CancellationToken = CancellationToken.None, - Progress = new Progress() - }); - } - private void ExtractFFMpeg(string tempFile, string targetFolder) { _logger.Debug("Extracting ffmpeg from {0}", tempFile); @@ -157,7 +187,7 @@ namespace MediaBrowser.ServerApplication.FFMpeg /// Extracts the fonts. /// /// The target path. - private async Task DownloadFonts(string targetPath) + private async Task DownloadFonts(string targetPath, IProgress progress) { try { @@ -171,7 +201,7 @@ namespace MediaBrowser.ServerApplication.FFMpeg if (!File.Exists(fontFile)) { - await DownloadFontFile(fontsDirectory, fontFilename).ConfigureAwait(false); + await DownloadFontFile(fontsDirectory, fontFilename, progress).ConfigureAwait(false); } await WriteFontConfigFile(fontsDirectory).ConfigureAwait(false); @@ -186,6 +216,8 @@ namespace MediaBrowser.ServerApplication.FFMpeg // Don't let the server crash because of this _logger.ErrorException("Error writing ffmpeg font files", ex); } + + progress.Report(100); } /// @@ -194,7 +226,7 @@ namespace MediaBrowser.ServerApplication.FFMpeg /// The fonts directory. /// The font filename. /// Task. - private async Task DownloadFontFile(string fontsDirectory, string fontFilename) + private async Task DownloadFontFile(string fontsDirectory, string fontFilename, IProgress progress) { var existingFile = Directory .EnumerateFiles(_appPaths.ProgramDataPath, fontFilename, SearchOption.AllDirectories) @@ -218,12 +250,14 @@ namespace MediaBrowser.ServerApplication.FFMpeg foreach (var url in _fontUrls) { + progress.Report(0); + try { tempFile = await _httpClient.GetTempFile(new HttpRequestOptions { Url = url, - Progress = new Progress() + Progress = progress }).ConfigureAwait(false); diff --git a/MediaBrowser.ServerApplication/Splash/SplashWindow.xaml b/MediaBrowser.ServerApplication/Splash/SplashWindow.xaml index 315c88cd2a..b35eadd06c 100644 --- a/MediaBrowser.ServerApplication/Splash/SplashWindow.xaml +++ b/MediaBrowser.ServerApplication/Splash/SplashWindow.xaml @@ -2,13 +2,18 @@ xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" Height="386.939" Width="664.49" WindowStartupLocation="CenterScreen" Title="Media Browser Server" ShowInTaskbar="True" WindowStyle="None" BorderThickness="1" BorderBrush="#cccccc" AllowsTransparency="True"> - - - + + + + + + + + - + diff --git a/MediaBrowser.ServerApplication/Splash/SplashWindow.xaml.cs b/MediaBrowser.ServerApplication/Splash/SplashWindow.xaml.cs index db2f1dbc47..29eb4bf45c 100644 --- a/MediaBrowser.ServerApplication/Splash/SplashWindow.xaml.cs +++ b/MediaBrowser.ServerApplication/Splash/SplashWindow.xaml.cs @@ -1,16 +1,6 @@ using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; +using System.ComponentModel; using System.Windows; -using System.Windows.Controls; -using System.Windows.Data; -using System.Windows.Documents; -using System.Windows.Input; -using System.Windows.Media; -using System.Windows.Media.Imaging; -using System.Windows.Shapes; namespace MediaBrowser.ServerApplication.Splash { @@ -19,10 +9,33 @@ namespace MediaBrowser.ServerApplication.Splash /// public partial class SplashWindow : Window { - public SplashWindow(Version version) + private readonly Progress _progress; + + public SplashWindow(Version version, Progress progress) { InitializeComponent(); lblStatus.Text = string.Format("Loading Media Browser Server\nVersion {0}...", version); + + _progress = progress; + + progress.ProgressChanged += progress_ProgressChanged; + } + + void progress_ProgressChanged(object sender, double e) + { + Dispatcher.InvokeAsync(() => + { + var width = e * 6.62; + + RectProgress.Width = width; + }); + } + + protected override void OnClosing(CancelEventArgs e) + { + _progress.ProgressChanged += progress_ProgressChanged; + + base.OnClosing(e); } } }