Ejemplo n.º 1
0
        private async void StartBackgroundUpdate()
        {
            if (this.State != UpdateState.NotStarted && this.State != UpdateState.Failed && this.State != UpdateState.UpToDate)
            {
                // Can only start updates from certain states.
                return;
            }

            this.State = UpdateState.DownloadingInfo;

            this.updateDownloadCancellationTokenSource = new CancellationTokenSource();

            await Task.Run(async() =>
            {
                try
                {
                    UpdateInfo updateInfo = await GetUpdateInfoAsync(CommonUtilities.Beta).ConfigureAwait(false);

                    if (updateInfo == null)
                    {
                        this.State = UpdateState.Failed;
                        this.logger.Log("Update download failed. Unable to get update info.");
                        return;
                    }

                    Version updateVersion = updateInfo.LatestVersion;
                    this.LatestVersion    = updateVersion;

                    if (updateVersion > Utilities.CurrentVersion)
                    {
                        // If an update is reported to be ready but the installer doesn't exist, clear out all the
                        // installer info and redownload.
                        string updateInstallerLocation = Config.UpdateInstallerLocation;
                        if (updateInstallerLocation != string.Empty && !File.Exists(updateInstallerLocation))
                        {
                            using (SQLiteTransaction transaction = Database.ThreadLocalConnection.BeginTransaction())
                            {
                                ClearUpdateMetadata();

                                transaction.Commit();
                            }

                            this.logger.Log("Downloaded update (" + updateInstallerLocation + ") could not be found. Re-downloading it.");
                        }

                        // If we have an installer downloaded, but there's a newer one out, clear out the downloaded update metadata
                        if (Config.UpdateInstallerLocation != string.Empty &&
                            Version.TryParse(Config.UpdateVersion, out Version downloadedUpdateVersion) &&
                            downloadedUpdateVersion.FillInWithZeroes() < updateVersion.FillInWithZeroes())
                        {
                            using (SQLiteTransaction transaction = Database.ThreadLocalConnection.BeginTransaction())
                            {
                                ClearUpdateMetadata();

                                transaction.Commit();
                            }
                        }

                        // If we have not finished the download update yet, start/resume the download.
                        if (Config.UpdateInstallerLocation == string.Empty)
                        {
                            string updateVersionText = updateVersion.ToShortString();

                            if (CommonUtilities.Beta)
                            {
                                updateVersionText += " Beta";
                            }

                            string newVersionStartedMessage = string.Format(MainRes.NewVersionDownloadStartedStatus, updateVersionText);
                            this.logger.Log(newVersionStartedMessage);

                            DispatchUtilities.BeginInvoke(() =>
                            {
                                this.logger.ShowStatus(newVersionStartedMessage);
                            });

                            this.State = UpdateState.DownloadingInstaller;
                            this.UpdateDownloadProgressFraction = 0;

                            string downloadLocation  = updateInfo.DownloadUrl;
                            string changelogLink     = updateInfo.ChangelogUrl;
                            string installerFileName = Path.GetFileName(downloadLocation);
                            string installerFilePath = Path.Combine(Utilities.UpdatesFolder, installerFileName);

                            Stream responseStream = null;
                            FileStream fileStream = null;

                            try
                            {
                                ServicePointManager.SecurityProtocol |= SecurityProtocolType.Tls12;
                                HttpClient client          = new HttpClient();
                                HttpRequestMessage request = new HttpRequestMessage(HttpMethod.Get, downloadLocation);

                                long bytesProgressTotal = 0;

                                if (File.Exists(installerFilePath))
                                {
                                    var fileInfo = new FileInfo(installerFilePath);

                                    request.Headers.Range = new RangeHeaderValue(fileInfo.Length, null);
                                    bytesProgressTotal    = fileInfo.Length;

                                    fileStream = new FileStream(installerFilePath, FileMode.Append, FileAccess.Write, FileShare.None);
                                }
                                else
                                {
                                    fileStream = new FileStream(installerFilePath, FileMode.Create, FileAccess.Write, FileShare.None);
                                }

                                var response   = await client.SendAsync(request).ConfigureAwait(false);
                                responseStream = await response.Content.ReadAsStreamAsync().ConfigureAwait(false);

                                byte[] downloadBuffer = new byte[2048];
                                int bytesRead;

                                while ((bytesRead = await responseStream.ReadAsync(downloadBuffer, 0, downloadBuffer.Length).ConfigureAwait(false)) > 0 && !this.updateDownloadCancellationTokenSource.Token.IsCancellationRequested)
                                {
                                    fileStream.Write(downloadBuffer, 0, bytesRead);
                                    bytesProgressTotal += bytesRead;

                                    this.UpdateDownloadProgressFraction = (double)bytesProgressTotal / response.Content.Headers.ContentLength.Value;
                                }

                                if (bytesRead == 0)
                                {
                                    using (SQLiteTransaction transaction = Database.ThreadLocalConnection.BeginTransaction())
                                    {
                                        Config.UpdateVersion           = updateVersion.ToString();
                                        Config.UpdateInstallerLocation = installerFilePath;
                                        Config.UpdateChangelogLocation = changelogLink;

                                        transaction.Commit();
                                    }

                                    this.State = UpdateState.InstallerReady;
                                    this.UpdateDownloadProgressFraction = 1;

                                    string downloadFinishedFormat = CustomConfig.UpdatePromptTiming == UpdatePromptTiming.OnExit
                                                                                ? MainRes.NewVersionDownloadFinishedStatus
                                                                                : MainRes.NewVersionDownloadFinishedOnLaunchStatus;
                                    string message = string.Format(downloadFinishedFormat, updateVersionText);
                                    this.logger.Log(message);
                                    this.logger.ShowStatus(message);
                                }
                                else
                                {
                                    // In this case the download must have been cancelled.
                                    this.State = UpdateState.NotStarted;
                                }
                            }
                            finally
                            {
                                responseStream?.Close();
                                fileStream?.Close();
                            }
                        }
                        else
                        {
                            this.State = UpdateState.InstallerReady;
                        }
                    }
                    else
                    {
                        this.State = UpdateState.UpToDate;
                    }
                }
                catch (Exception exception)
                {
                    this.State = UpdateState.Failed;
                    this.logger.Log("Update download failed." + Environment.NewLine + exception);
                }
                finally
                {
                    this.updateDownloadCancellationTokenSource?.Dispose();
                    this.updateDownloadCancellationTokenSource = null;
                }

                if (this.State == UpdateState.InstallerReady && CustomConfig.UpdatePromptTiming == UpdatePromptTiming.OnLaunch)
                {
                    DispatchUtilities.BeginInvoke(() =>
                    {
                        if (this.PromptToApplyUpdate(relaunchWhenComplete: true))
                        {
                            StaticResolver.Resolve <MainViewModel>().Exit.Execute(null);
                        }
                    });
                }
            });
        }
Ejemplo n.º 2
0
        public bool TryUpdateSelectedPreset(PresetViewModel value)
        {
            if (value == null || this.selectedPreset == value)
            {
                return(false);
            }

            PresetViewModel previouslySelectedPreset = this.selectedPreset;
            bool            changeSelectedPreset     = true;

            if (this.selectedPreset != null && this.selectedPreset.Preset.IsModified)
            {
                string           dialogMessage;
                string           dialogTitle;
                MessageBoxButton buttons;

                if (this.selectedPreset.Preset.IsBuiltIn)
                {
                    dialogMessage = MainRes.PresetDiscardConfirmMessage;
                    dialogTitle   = MainRes.PresetDiscardConfirmTitle;
                    buttons       = MessageBoxButton.OKCancel;
                }
                else
                {
                    dialogMessage = MainRes.SaveChangesPresetMessage;
                    dialogTitle   = MainRes.SaveChangesPresetTitle;
                    buttons       = MessageBoxButton.YesNoCancel;
                }

                MessageBoxResult dialogResult = Utilities.MessageBox.Show(
                    this.main,
                    dialogMessage,
                    dialogTitle,
                    buttons);
                if (dialogResult == MessageBoxResult.Yes)
                {
                    // Yes, we wanted to save changes
                    this.SavePreset();
                }
                else if (dialogResult == MessageBoxResult.No || dialogResult == MessageBoxResult.OK)
                {
                    // No, we didn't want to save changes or OK, we wanted to discard changes.
                    this.RevertPreset(userInitiated: false);
                }
                else if (dialogResult == MessageBoxResult.Cancel)
                {
                    // Queue up an action to switch back to this preset.
                    int currentPresetIndex = this.AllPresets.IndexOf(this.selectedPreset);

                    DispatchUtilities.BeginInvoke(() =>
                    {
                        this.SelectedPreset = this.AllPresets[currentPresetIndex];
                    });

                    changeSelectedPreset = false;
                }
            }

            this.selectedPreset            = value;
            this.selectedPreset.IsSelected = true;             // For TreeView

            if (changeSelectedPreset)
            {
                this.NotifySelectedPresetChanged();

                if (previouslySelectedPreset != null)
                {
                    Config.LastPresetIndex = this.AllPresets.IndexOf(this.selectedPreset);
                }

                // If we're switching away from a temporary queue preset, remove it.
                if (previouslySelectedPreset != null && previouslySelectedPreset.Preset.IsQueue && previouslySelectedPreset != value)
                {
                    this.AllPresets.Remove(previouslySelectedPreset);
                }
            }

            return(changeSelectedPreset);
        }
Ejemplo n.º 3
0
        private void ProcessPreviewImageWork(object state)
        {
            PreviewImageJob imageJob;
            bool            workLeft = true;

            while (workLeft)
            {
                lock (this.imageSync)
                {
                    if (this.previewImageWorkQueue.Count == 0)
                    {
                        this.previewImageQueueProcessing = false;
                        return;
                    }

                    imageJob = this.previewImageWorkQueue.Dequeue();
                    while (imageJob.UpdateVersion < updateVersion)
                    {
                        if (this.previewImageWorkQueue.Count == 0)
                        {
                            this.previewImageQueueProcessing = false;
                            return;
                        }

                        imageJob = this.previewImageWorkQueue.Dequeue();
                    }
                }

                string imagePath = Path.Combine(
                    Utilities.ImageCacheFolder,
                    Process.GetCurrentProcess().Id.ToString(CultureInfo.InvariantCulture),
                    imageJob.UpdateVersion.ToString(CultureInfo.InvariantCulture),
                    imageJob.PreviewIndex.ToString(CultureInfo.InvariantCulture) + ".bmp");
                BitmapSource imageSource = null;

                // Check the disc cache for the image
                lock (imageJob.ImageFileSync)
                {
                    if (File.Exists(imagePath))
                    {
                        Uri imageUri;
                        if (Uri.TryCreate(imagePath, UriKind.Absolute, out imageUri))
                        {
                            // When we read from disc cache the image is already transformed.
                            var bitmapImage = new BitmapImage();
                            bitmapImage.BeginInit();
                            bitmapImage.CacheOption = BitmapCacheOption.OnLoad;
                            bitmapImage.UriSource   = imageUri;
                            bitmapImage.EndInit();
                            bitmapImage.Freeze();

                            imageSource = bitmapImage;
                        }
                        else
                        {
                            StaticResolver.Resolve <IAppLogger>().LogError($"Could not load cached preview image from {imagePath} . Did not parse as a URI.");
                        }
                    }
                }

                if (imageSource == null && !imageJob.ScanInstance.IsDisposed)
                {
                    // Make a HandBrake call to get the image
                    imageSource = BitmapUtilities.ConvertToBitmapImage(BitmapUtilities.ConvertByteArrayToBitmap(imageJob.ScanInstance.GetPreview(imageJob.Profile.CreatePreviewSettings(imageJob.Title), imageJob.PreviewIndex, imageJob.Profile.DeinterlaceType != VCDeinterlace.Off)));

                    // Transform the image as per rotation and reflection settings
                    VCProfile profile = imageJob.Profile;
                    if (profile.FlipHorizontal || profile.FlipVertical || profile.Rotation != VCPictureRotation.None)
                    {
                        imageSource = CreateTransformedBitmap(imageSource, profile);
                    }

                    // Start saving the image file in the background and continue to process the queue.
                    ThreadPool.QueueUserWorkItem(this.BackgroundFileSave, new SaveImageJob
                    {
                        PreviewNumber = imageJob.PreviewIndex,
                        UpdateVersion = imageJob.UpdateVersion,
                        FilePath      = imagePath,
                        Image         = imageSource,
                        ImageFileSync = imageJob.ImageFileSync
                    });
                }

                lock (this.imageSync)
                {
                    if (imageJob.UpdateVersion == updateVersion)
                    {
                        this.previewImageCache[imageJob.PreviewIndex] = imageSource;
                        int previewIndex = imageJob.PreviewIndex;
                        DispatchUtilities.BeginInvoke(() =>
                        {
                            this.ImageLoaded?.Invoke(this, new PreviewImageLoadInfo {
                                PreviewImage = imageSource, PreviewIndex = previewIndex
                            });
                        });
                    }

                    if (this.previewImageWorkQueue.Count == 0)
                    {
                        workLeft = false;
                        this.previewImageQueueProcessing = false;
                    }
                }
            }
        }
Ejemplo n.º 4
0
        public PickerWindowViewModel()
        {
            using (this.autoChangeTracker.TrackAutoChange())
            {
                this.RegisterPickerProperties();

                this.pickersService.WhenAnyValue(x => x.SelectedPicker.Picker)
                .Subscribe(x =>
                {
                    using (this.autoChangeTracker.TrackAutoChange())
                    {
                        this.RaiseAllChanged();

                        // When we are swapping active pickers, update the local properties.
                        if (!this.userModifyingOutputDirectory)
                        {
                            this.OutputDirectoryOverride = this.Picker.OutputDirectoryOverride;
                        }

                        if (!this.userModifyingNameFormat)
                        {
                            this.NameFormatOverride = this.Picker.NameFormatOverride;
                        }

                        if (!this.userModifyingEncodingPreset)
                        {
                            this.PopulateEncodingPreset(this.Picker.UseEncodingPreset);
                        }
                    }
                });

                this.pickersService.WhenAnyValue(x => x.SelectedPicker.Picker.AudioLanguageCodes).Subscribe(audioLanguageCodes =>
                {
                    using (this.autoChangeTracker.TrackAutoChange())
                    {
                        this.audioLanguages.Edit(audioLanguagesInnerList =>
                        {
                            audioLanguagesInnerList.Clear();

                            if (audioLanguageCodes == null)
                            {
                                audioLanguagesInnerList.Add(new LanguageViewModel(this)
                                {
                                    Code = LanguageUtilities.GetDefaultLanguageCode()
                                });
                                return;
                            }

                            audioLanguagesInnerList.AddRange(audioLanguageCodes.Select(l => new LanguageViewModel(this)
                            {
                                Code = l
                            }));
                        });
                    }
                });

                var audioLanguagesObservable = this.audioLanguages.Connect();
                audioLanguagesObservable.Bind(this.AudioLanguagesBindable).Subscribe();
                audioLanguagesObservable.WhenAnyPropertyChanged().Subscribe(_ =>
                {
                    if (!this.autoChangeTracker.OperationInProgress)
                    {
                        this.HandleAudioLanguageUpdate();
                    }
                });

                this.pickersService.WhenAnyValue(x => x.SelectedPicker.Picker.SubtitleLanguageCodes).Subscribe(subtitleLanguageCodes =>
                {
                    using (this.autoChangeTracker.TrackAutoChange())
                    {
                        this.subtitleLanguages.Edit(subtitleLanguagesInnerList =>
                        {
                            subtitleLanguagesInnerList.Clear();

                            if (subtitleLanguageCodes == null)
                            {
                                subtitleLanguagesInnerList.Add(new LanguageViewModel(this)
                                {
                                    Code = LanguageUtilities.GetDefaultLanguageCode()
                                });
                                return;
                            }

                            subtitleLanguagesInnerList.AddRange(subtitleLanguageCodes.Select(l => new LanguageViewModel(this)
                            {
                                Code = l
                            }));
                        });
                    }
                });

                var subtitleLanguagesObservable = this.subtitleLanguages.Connect();
                subtitleLanguagesObservable.Bind(this.SubtitleLanguagesBindable).Subscribe();
                subtitleLanguagesObservable.WhenAnyPropertyChanged().Subscribe(_ =>
                {
                    if (!this.autoChangeTracker.OperationInProgress)
                    {
                        this.HandleSubtitleLanguageUpdate();
                    }
                });

                // HasMultipleAudioLanguages
                IObservable <int> audioLanguageCountObservable = audioLanguagesObservable
                                                                 .Count()
                                                                 .StartWith(this.audioLanguages.Count);
                IObservable <bool> hasMultipleAudioLanguagesObservable = audioLanguageCountObservable
                                                                         .Select(count => count > 1);
                hasMultipleAudioLanguagesObservable.ToProperty(this, x => x.HasMultipleAudioLanguages, out this.hasMultipleAudioLanguages);

                // AudioFirstTrackLabel
                hasMultipleAudioLanguagesObservable
                .Select(hasMultipleAudioLanguages =>
                {
                    return(hasMultipleAudioLanguages ? PickerRes.FirstTrackOfEachLanguageRadioButton : PickerRes.FirstTrackRadioButton);
                })
                .ToProperty(this, x => x.AudioFirstTrackLabel, out this.audioFirstTrackLabel);

                // AudioAllTracksLabel
                hasMultipleAudioLanguagesObservable
                .Select(hasMultipleAudioLanguages =>
                {
                    return(hasMultipleAudioLanguages ? PickerRes.AllTracksForTheseLanguagesRadioButton : PickerRes.AllTracksForThisLanguageRadioButton);
                })
                .ToProperty(this, x => x.AudioAllTracksLabel, out this.audioAllTracksLabel);

                // HasNoAudioLanguages
                audioLanguageCountObservable
                .Select(count => count == 0)
                .ToProperty(this, x => x.HasNoAudioLanguages, out this.hasNoAudioLanguages);

                // HasMultipleSubtitleLanguages
                IObservable <int> subtitleLanguageCountObservable = subtitleLanguagesObservable
                                                                    .Count()
                                                                    .StartWith(this.subtitleLanguages.Count);
                IObservable <bool> hasMultipleSubtitleLanguagesObservable = subtitleLanguageCountObservable
                                                                            .Select(count => count > 1);
                hasMultipleSubtitleLanguagesObservable.ToProperty(this, x => x.HasMultipleSubtitleLanguages, out this.hasMultipleSubtitleLanguages);

                // SubtitleFirstTrackLabel
                hasMultipleSubtitleLanguagesObservable
                .Select(hasMultipleSubtitleLanguages =>
                {
                    return(hasMultipleSubtitleLanguages ? PickerRes.FirstTrackOfEachLanguageRadioButton : PickerRes.FirstTrackRadioButton);
                })
                .ToProperty(this, x => x.SubtitleFirstTrackLabel, out this.subtitleFirstTrackLabel);

                // SubtitleAllTracksLabel
                hasMultipleSubtitleLanguagesObservable
                .Select(hasMultipleSubtitleLanguages =>
                {
                    return(hasMultipleSubtitleLanguages ? PickerRes.AllTracksForTheseLanguagesRadioButton : PickerRes.AllTracksForThisLanguageRadioButton);
                })
                .ToProperty(this, x => x.SubtitleAllTracksLabel, out this.subtitleAllTracksLabel);

                // HasNoSubtitleLanguages
                subtitleLanguageCountObservable
                .Select(count => count == 0)
                .ToProperty(this, x => x.HasNoSubtitleLanguages, out this.hasNoSubtitleLanguages);

                // SubtitleQuantityClass
                this.WhenAnyValue(x => x.SubtitleSelectionMode, x => x.SubtitleIndices, x => x.HasMultipleSubtitleLanguages, x => x.SubtitleLanguageAll, (selectionMode, subtitleIndices, hasMultipleLanguages, subtitleLanguageAll) =>
                {
                    switch (selectionMode)
                    {
                    case SubtitleSelectionMode.Disabled:
                    case SubtitleSelectionMode.None:
                        return(SubtitleQuantityClass.None);

                    case SubtitleSelectionMode.First:
                    case SubtitleSelectionMode.ForeignAudioSearch:
                        return(SubtitleQuantityClass.Single);

                    case SubtitleSelectionMode.ByIndex:
                        return(ParseUtilities.ParseCommaSeparatedListToPositiveIntegers(subtitleIndices).Count > 1 ? SubtitleQuantityClass.Multiple : SubtitleQuantityClass.Single);

                    case SubtitleSelectionMode.Language:
                        if (hasMultipleLanguages)
                        {
                            return(SubtitleQuantityClass.Multiple);
                        }

                        return(subtitleLanguageAll ? SubtitleQuantityClass.Multiple : SubtitleQuantityClass.Single);

                    case SubtitleSelectionMode.All:
                        return(SubtitleQuantityClass.Multiple);

                    default:
                        throw new ArgumentOutOfRangeException(nameof(selectionMode), selectionMode, null);
                    }
                }).ToProperty(this, x => x.SubtitleQuantityClass, out this.subtitleQuantityClass);

                // ShowMarkFirstAsDefaultCheckBox
                this.WhenAnyValue(x => x.SubtitleQuantityClass, x => x.SubtitleSelectionMode, (subtitleQuantityClass, selectionMode) =>
                {
                    return(subtitleQuantityClass == SubtitleQuantityClass.Multiple && selectionMode != SubtitleSelectionMode.ByIndex);
                }).ToProperty(this, x => x.ShowMarkFirstAsDefaultCheckBox, out this.showMarkFirstAsDefaultCheckBox);

                this.pickersService.WhenAnyValue(x => x.SelectedPicker.Picker.IsDefault, x => x.SelectedPicker.Picker.IsModified, (isDefault, isModified) => !isDefault && !isModified).ToProperty(this, x => x.DeleteButtonVisible, out this.deleteButtonVisible);

                this.pickersService.WhenAnyValue(x => x.SelectedPicker.Picker.DisplayName, x => x.SelectedPicker.Picker.IsModified, (displayName, isModified) =>
                {
                    string windowTitle2 = string.Format(PickerRes.WindowTitle, displayName);
                    if (isModified)
                    {
                        windowTitle2 += " *";
                    }

                    return(windowTitle2);
                }).ToProperty(this, x => x.WindowTitle, out this.windowTitle);

                // Whenever the output directory override is disabled, used the config.
                this.WhenAnyValue(x => x.OutputDirectoryOverrideEnabled).Subscribe(directoryOverrideEnabled =>
                {
                    if (!directoryOverrideEnabled)
                    {
                        this.OutputDirectoryOverride = Config.AutoNameOutputFolder;
                    }
                    else
                    {
                        this.OutputDirectoryOverride = this.Picker.OutputDirectoryOverride;
                    }
                });

                // Whenever the name format override is disabled, used the config.
                this.WhenAnyValue(x => x.NameFormatOverrideEnabled).Subscribe(nameFormatOverrideEnabled =>
                {
                    if (!nameFormatOverrideEnabled)
                    {
                        this.NameFormatOverride = AutoNameCustomFormat;
                    }
                    else
                    {
                        this.NameFormatOverride = this.Picker.NameFormatOverride;
                    }
                });

                // Whenever UseEncodingPreset is false, set the selected VM to null.
                this.WhenAnyValue(x => x.UseEncodingPreset).Subscribe(useEncodingPreset => { this.PopulateEncodingPreset(useEncodingPreset); });

                // Update the underlying picker when our local properties change.
                // Don't need to raise another changed event as our local property setter already raises it.
                this.WhenAnyValue(x => x.OutputDirectoryOverride).Skip(1).Subscribe(directoryOverride =>
                {
                    this.userModifyingOutputDirectory = true;
                    this.UpdatePickerProperty(nameof(this.Picker.OutputDirectoryOverride), directoryOverride, raisePropertyChanged: false);
                    this.outputPathService.GenerateOutputFileName();
                    this.userModifyingOutputDirectory = false;
                });

                this.WhenAnyValue(x => x.NameFormatOverride).Skip(1).Subscribe(nameFormatOverride =>
                {
                    this.userModifyingNameFormat = true;
                    this.UpdatePickerProperty(nameof(this.Picker.NameFormatOverride), nameFormatOverride, raisePropertyChanged: false);
                    this.outputPathService.GenerateOutputFileName();
                    this.userModifyingNameFormat = false;
                });

                this.WhenAnyValue(x => x.SelectedPreset).Subscribe(selectedPreset =>
                {
                    this.userModifyingEncodingPreset = true;
                    string presetName = selectedPreset == null ? null : selectedPreset.Preset.Name;
                    this.UpdatePickerProperty(nameof(this.Picker.EncodingPreset), presetName, raisePropertyChanged: false);
                    if (this.UseEncodingPreset && selectedPreset != null)
                    {
                        if (!this.PresetsService.TryUpdateSelectedPreset(selectedPreset))
                        {
                            DispatchUtilities.BeginInvoke(() =>
                            {
                                this.SelectedPreset = this.PresetsService.SelectedPreset;
                            });
                        }
                    }

                    this.userModifyingEncodingPreset = false;
                });
            }
        }
Ejemplo n.º 5
0
        public Main()
        {
            Ioc.Container.RegisterSingleton <Main>(() => this);
            this.InitializeComponent();

            this.sourceRow.Height = new GridLength(Config.SourcePaneHeightStar, GridUnitType.Star);
            this.queueRow.Height  = new GridLength(Config.QueuePaneHeightStar, GridUnitType.Star);

            this.Activated += (sender, args) =>
            {
                DispatchUtilities.BeginInvoke(async() =>
                {
                    // Need to yield here for some reason, otherwise the activation is blocked.
                    await Task.Yield();
                    this.toastNotificationService.Clear();
                });
            };

            this.notifyIcon = new NotifyIcon
            {
                Visible = false
            };
            this.notifyIcon.Click       += (sender, args) => { this.RestoreWindow(); };
            this.notifyIcon.DoubleClick += (sender, args) => { this.RestoreWindow(); };

            StreamResourceInfo streamResourceInfo = System.Windows.Application.GetResourceStream(new Uri("pack://application:,,,/VidCoder_icon.ico"));

            if (streamResourceInfo != null)
            {
                Stream iconStream = streamResourceInfo.Stream;
                this.notifyIcon.Icon = new Icon(iconStream);
            }

            this.RefreshQueueColumns();
            this.LoadCompletedColumnWidths();

#if DEBUG
            var debugDropDown = new DropDownButton {
                Header = "Debug"
            };
            var queueFromJsonItem = new Fluent.MenuItem {
                Header = "Queue job from JSON..."
            };

            queueFromJsonItem.Click += (sender, args) =>
            {
                if (!this.viewModel.HasVideoSource)
                {
                    StaticResolver.Resolve <IMessageBoxService>().Show("Must open source before adding queue job from JSON");
                    return;
                }

                EncodeJobViewModel    jobViewModel = this.viewModel.CreateEncodeJobVM();
                DebugEncodeJsonDialog dialog       = new DebugEncodeJsonDialog();
                dialog.ShowDialog();

                if (!string.IsNullOrWhiteSpace(dialog.EncodeJson))
                {
                    try
                    {
                        JsonEncodeObject encodeObject = JsonConvert.DeserializeObject <JsonEncodeObject>(dialog.EncodeJson);

                        jobViewModel.DebugEncodeJsonOverride = dialog.EncodeJson;
                        jobViewModel.Job.FinalOutputPath     = encodeObject.Destination.File;
                        jobViewModel.Job.SourcePath          = encodeObject.Source.Path;

                        this.processingService.Queue(jobViewModel);
                    }
                    catch (Exception exception)
                    {
                        MessageBox.Show(this, "Could not parse encode JSON:" + Environment.NewLine + Environment.NewLine + exception.ToString());
                    }
                }
            };

            debugDropDown.Items.Add(queueFromJsonItem);

            var throwExceptionItem = new Fluent.MenuItem {
                Header = "Throw exception"
            };
            throwExceptionItem.Click += (sender, args) =>
            {
                throw new InvalidOperationException("Rats.");
            };

            debugDropDown.Items.Add(throwExceptionItem);

            var addLogItem = new Fluent.MenuItem {
                Header = "Add 1 log item"
            };
            addLogItem.Click += (sender, args) =>
            {
                StaticResolver.Resolve <IAppLogger>().Log("This is a log item");
            };

            debugDropDown.Items.Add(addLogItem);

            var addTenLogItems = new Fluent.MenuItem {
                Header = "Add 10 log items"
            };
            addTenLogItems.Click += (sender, args) =>
            {
                for (int i = 0; i < 10; i++)
                {
                    StaticResolver.Resolve <IAppLogger>().Log("This is a log item");
                }
            };

            debugDropDown.Items.Add(addTenLogItems);

            var doAnActionItem = new Fluent.MenuItem {
                Header = "Perform action"
            };
            doAnActionItem.Click += (sender, args) =>
            {
                var app = (App)System.Windows.Application.Current;
                app.ChangeTheme(new Uri("/Themes/Dark.xaml", UriKind.Relative));
            };

            debugDropDown.Items.Add(doAnActionItem);

            this.toolsRibbonGroupBox.Items.Add(debugDropDown);
#endif

            this.DataContextChanged += this.OnDataContextChanged;
            TheDispatcher            = this.Dispatcher;

            this.statusText.Opacity = 0.0;

            NameScope.SetNameScope(this, new NameScope());
            this.RegisterName("StatusText", this.statusText);

            var storyboard = (Storyboard)this.FindResource("StatusTextStoryboard");
            storyboard.Completed += (sender, args) =>
            {
                this.statusText.Visibility = Visibility.Collapsed;
            };

            this.presetTreeViewContainer.PresetTreeView.OnHierarchyMouseUp += (sender, args) =>
            {
                this.presetButton.IsDropDownOpen = false;
            };

            this.presetButton.DropDownOpened += (sender, args) =>
            {
                var item = UIUtilities.FindDescendant <TreeViewItem>(this.presetTreeViewContainer.PresetTreeView, viewItem =>
                {
                    return(viewItem.Header == this.viewModel.PresetsService.SelectedPreset);
                });

                if (item != null)
                {
                    UIUtilities.BringIntoView(item);
                }
            };

            this.Loaded += (e, o) =>
            {
                this.RestoredWindowState = this.WindowState;
            };

            this.statusService.MessageShown += (o, e) =>
            {
                this.ShowStatusMessage(e.Value);
            };
        }
Ejemplo n.º 6
0
 private void previewImageRefreshTimer_Elapsed(object sender, System.Timers.ElapsedEventArgs e)
 {
     this.waitingOnRefresh     = false;
     this.lastImageRefreshTime = DateTime.MinValue;
     DispatchUtilities.BeginInvoke(this.RefreshPreviews);
 }
Ejemplo n.º 7
0
        public static void SetVideo(this IPreviewFrame previewFrame, Action onCompleted, Action onFailed, IObservable <double> volume)
        {
            Grid holder = previewFrame.Holder;

            if (HasChild <MediaElement>(holder))
            {
                // There is already a video in here.
                RemoveImage(holder);
                return;
            }

            // Close any video that was there before.
            RemoveVideo(holder);

            // Add on a new video
            var mediaElement = new MediaElement
            {
                Stretch = Stretch.Fill,
                Opacity = 0
            };

            var viewModel = (PreviewWindowViewModel)previewFrame.Holder.DataContext;

            mediaElement.SetBinding(MediaElement.SourceProperty, nameof(viewModel.PreviewFilePath));
            mediaElement.LoadedBehavior   = MediaState.Manual;
            mediaElement.ScrubbingEnabled = true;
            mediaElement.MediaOpened     += (sender, args) =>
            {
                if (mediaElement.NaturalDuration.HasTimeSpan)
                {
                    viewModel.PreviewVideoDuration = mediaElement.NaturalDuration.TimeSpan;
                }
                else
                {
                    viewModel.PreviewVideoDuration = TimeSpan.Zero;
                }

                // Video starts out black so we want to hold it at the start until it displays fully.
                mediaElement.Pause();

                DispatchUtilities.BeginInvoke(() =>
                {
                    OnVideoPlaying(holder);
                    mediaElement.Play();
                });
            };

            mediaElement.MediaFailed += (sender, args) =>
            {
                onFailed();
            };

            mediaElement.MediaEnded += (sender, args) =>
            {
                onCompleted();
            };

            volume.Subscribe(v =>
            {
                mediaElement.Volume = v;
            });

            mediaElement.Play();

            holder.Children.Add(mediaElement);
        }
        public VideoFiltersPanelViewModel(EncodingWindowViewModel encodingWindowViewModel)
            : base(encodingWindowViewModel)
        {
            this.AutomaticChange = true;

            this.RegisterProfileProperties();

            this.DetelecineChoices = this.GetFilterPresetChoices(hb_filter_ids.HB_FILTER_DETELECINE);

            this.DeinterlaceChoices = new List <ComboChoice <VCDeinterlace> >
            {
                new ComboChoice <VCDeinterlace>(VCDeinterlace.Off, CommonRes.Off),
                new ComboChoice <VCDeinterlace>(VCDeinterlace.Yadif, EnumsRes.Deinterlace_Yadif),
                new ComboChoice <VCDeinterlace>(VCDeinterlace.Decomb, EnumsRes.Deinterlace_Decomb),
            };

            this.CombDetectChoices = this.GetFilterPresetChoices(hb_filter_ids.HB_FILTER_COMB_DETECT, "CombDetect_");

            this.DenoiseChoices = new List <ComboChoice <VCDenoise> >
            {
                new ComboChoice <VCDenoise>(VCDenoise.Off, CommonRes.Off),
                new ComboChoice <VCDenoise>(VCDenoise.hqdn3d, EnumsRes.Denoise_HQDN3D),
                new ComboChoice <VCDenoise>(VCDenoise.NLMeans, EnumsRes.Denoise_NLMeans),
            };

            this.DenoiseTuneChoices = this.GetFilterTuneChoices(hb_filter_ids.HB_FILTER_NLMEANS, "DenoiseTune_");

            this.SharpenChoices = new List <ComboChoice <VCSharpen> >
            {
                new ComboChoice <VCSharpen>(VCSharpen.Off, CommonRes.Off),
                new ComboChoice <VCSharpen>(VCSharpen.UnSharp, EnumsRes.Sharpen_UnSharp),
                new ComboChoice <VCSharpen>(VCSharpen.LapSharp, EnumsRes.Sharpen_LapSharp),
            };



            // CustomDetelecineVisible
            this.WhenAnyValue(x => x.Detelecine, detelecine =>
            {
                return(detelecine == "custom");
            }).ToProperty(this, x => x.CustomDetelecineVisible, out this.customDetelecineVisible);

            // DeinterlacePresetChoices
            this.WhenAnyValue(x => x.DeinterlaceType)
            .Select(deinterlaceType =>
            {
                if (deinterlaceType == VCDeinterlace.Off)
                {
                    return(new List <ComboChoice>());
                }

                return(this.GetFilterPresetChoices(GetDeinterlaceFilter(deinterlaceType), "DeinterlacePreset_"));
            }).ToProperty(this, x => x.DeinterlacePresetChoices, out this.deinterlacePresetChoices);

            // DeinterlacePresetVisible
            this.WhenAnyValue(x => x.DeinterlaceType)
            .Select(deinterlaceType =>
            {
                return(deinterlaceType != VCDeinterlace.Off);
            }).ToProperty(this, x => x.DeinterlacePresetVisible, out this.deinterlacePresetVisible);

            // CustomDeinterlaceVisible
            this.WhenAnyValue(x => x.DeinterlaceType, x => x.DeinterlacePreset, (deinterlaceType, deinterlacePreset) =>
            {
                return(deinterlaceType != VCDeinterlace.Off && deinterlacePreset == "custom");
            }).ToProperty(this, x => x.CustomDeinterlaceVisible, out this.customDeinterlaceVisible);

            // CustomDeinterlaceToolTip
            this.WhenAnyValue(x => x.DeinterlaceType, deinterlaceType =>
            {
                if (deinterlaceType == VCDeinterlace.Off)
                {
                    return(string.Empty);
                }

                return(GetCustomFilterToolTip(GetDeinterlaceFilter(deinterlaceType)));
            }).ToProperty(this, x => x.CustomDeinterlaceToolTip, out this.customDeinterlaceToolTip);

            // CustomCombDetectVisible
            this.WhenAnyValue(x => x.CombDetect, combDetect =>
            {
                return(combDetect == "custom");
            }).ToProperty(this, x => x.CustomCombDetectVisible, out this.customCombDetectVisible);

            // DenoisePresetVisible
            this.WhenAnyValue(x => x.DenoiseType, denoise =>
            {
                return(denoise != VCDenoise.Off);
            }).ToProperty(this, x => x.DenoisePresetVisible, out this.denoisePresetVisible);

            // DenoisePresetChoices
            this.WhenAnyValue(x => x.DenoiseType)
            .Select(denoiseType =>
            {
                if (denoiseType == VCDenoise.Off)
                {
                    return(new List <ComboChoice>());
                }

                return(this.GetFilterPresetChoices(GetDenoiseFilter(denoiseType), "DenoisePreset_"));
            }).ToProperty(this, x => x.DenoisePresetChoices, out this.denoisePresetChoices);

            // DenoiseTuneVisible
            this.WhenAnyValue(x => x.DenoiseType, x => x.DenoisePreset, (denoiseType, denoisePreset) =>
            {
                return(denoiseType == VCDenoise.NLMeans && denoisePreset != "custom");
            }).ToProperty(this, x => x.DenoiseTuneVisible, out this.denoiseTuneVisible);

            // CustomDenoiseVisible
            this.WhenAnyValue(x => x.DenoiseType, x => x.DenoisePreset, (denoiseType, denoisePreset) =>
            {
                return(denoiseType != VCDenoise.Off && denoisePreset == "custom");
            }).ToProperty(this, x => x.CustomDenoiseVisible, out this.customDenoiseVisible);

            // CustomDenoiseToolTip
            this.WhenAnyValue(x => x.DenoiseType, denoiseType =>
            {
                if (denoiseType == VCDenoise.Off)
                {
                    return(string.Empty);
                }

                return(GetCustomFilterToolTip(GetDenoiseFilter(denoiseType)));
            }).ToProperty(this, x => x.CustomDenoiseToolTip, out this.customDenoiseToolTip);

            // SharpenPresetChoices
            this.WhenAnyValue(x => x.SharpenType)
            .Select(sharpenType =>
            {
                if (sharpenType == VCSharpen.Off)
                {
                    return(new List <ComboChoice>());
                }

                return(this.GetFilterPresetChoices(GetSharpenFilter(sharpenType)));
            }).ToProperty(this, x => x.SharpenPresetChoices, out this.sharpenPresetChoices);

            // SharpenPresetVisible
            this.WhenAnyValue(x => x.SharpenType)
            .Select(sharpenType =>
            {
                return(sharpenType != VCSharpen.Off);
            }).ToProperty(this, x => x.SharpenPresetVisible, out this.sharpenPresetVisible);

            // SharpenTuneChoices
            this.WhenAnyValue(x => x.SharpenType)
            .Select(sharpenType =>
            {
                if (sharpenType == VCSharpen.Off)
                {
                    return(new List <ComboChoice>());
                }

                return(this.GetFilterTuneChoices(GetSharpenFilter(sharpenType)));
            }).ToProperty(this, x => x.SharpenTuneChoices, out this.sharpenTuneChoices);

            // SharpenTuneVisible
            this.WhenAnyValue(x => x.SharpenType, x => x.SharpenPreset, (sharpenType, sharpenPreset) =>
            {
                return(sharpenType != VCSharpen.Off && sharpenPreset != "custom");
            }).ToProperty(this, x => x.SharpenTuneVisible, out this.sharpenTuneVisible);

            // CustomSharpenVisible
            this.WhenAnyValue(x => x.SharpenType, x => x.SharpenPreset, (sharpenType, sharpenPreset) =>
            {
                return(sharpenType != VCSharpen.Off && sharpenPreset == "custom");
            }).ToProperty(this, x => x.CustomSharpenVisible, out this.customSharpenVisible);

            // CustomSharpenToolTip
            this.WhenAnyValue(x => x.SharpenType)
            .Select(sharpenType =>
            {
                if (sharpenType == VCSharpen.Off)
                {
                    return(string.Empty);
                }

                return(GetCustomFilterToolTip(GetSharpenFilter(sharpenType)));
            }).ToProperty(this, x => x.CustomSharpenToolTip, out this.customSharpenToolTip);

            // DeblockText
            this.WhenAnyValue(x => x.Deblock, deblock =>
            {
                if (deblock >= MinDeblock)
                {
                    return(deblock.ToString(CultureInfo.CurrentCulture));
                }

                return(CommonRes.Off);
            }).ToProperty(this, x => x.DeblockText, out this.deblockText);

            // The deinterlace and denoise presets need another nudge to change after the lists have changed.
            this.WhenAnyValue(x => x.DeinterlaceType)
            .Subscribe(_ =>
            {
                DispatchUtilities.BeginInvoke(() =>
                {
                    this.RaisePropertyChanged(nameof(this.DeinterlacePreset));
                });
            });

            this.WhenAnyValue(x => x.DenoiseType)
            .Subscribe(_ =>
            {
                DispatchUtilities.BeginInvoke(() =>
                {
                    this.RaisePropertyChanged(nameof(this.DenoisePreset));
                });
            });

            this.AutomaticChange = false;
        }
Ejemplo n.º 9
0
        private void GeneratePreviewImpl()
        {
            this.job = this.mainViewModel.EncodeJob;

            this.PreviewPercentComplete = 0;
            this.EncodeState            = PreviewEncodeState.EncodeStarting;
            this.cancelPending          = false;
            this.encodeCancelled        = false;

            this.SetPreviewFilePath();

            this.job.OutputPath = this.previewFilePath;

            this.encodeProxy = Utilities.CreateEncodeProxy();
            this.encodeProxy.EncodeStarted += (o, e) =>
            {
                DispatchUtilities.BeginInvoke(() =>
                {
                    this.EncodeState = PreviewEncodeState.Encoding;
                    if (this.cancelPending)
                    {
                        this.CancelPreviewImpl();
                    }
                });
            };
            this.encodeProxy.EncodeProgress += (o, e) =>
            {
                double totalWeight;
                double completeWeight;
                if (e.PassCount == 1)
                {
                    // Single pass, no subtitle scan
                    totalWeight    = 1;
                    completeWeight = e.FractionComplete;
                }
                else if (e.PassCount == 2 && e.PassId <= 0)
                {
                    // Single pass with subtitle scan
                    totalWeight = 1 + SubtitleScanCost;
                    if (e.PassId == -1)
                    {
                        // In subtitle scan
                        completeWeight = e.FractionComplete * SubtitleScanCost;
                    }
                    else
                    {
                        // In normal pass
                        completeWeight = SubtitleScanCost + e.FractionComplete;
                    }
                }
                else if (e.PassCount == 2 && e.PassId >= 1)
                {
                    // Two normal passes
                    totalWeight = 2;

                    if (e.PassId == 1)
                    {
                        // First pass
                        completeWeight = e.FractionComplete;
                    }
                    else
                    {
                        // Second pass
                        completeWeight = 1 + e.FractionComplete;
                    }
                }
                else
                {
                    // Two normal passes with subtitle scan
                    totalWeight = 2 + SubtitleScanCost;

                    if (e.PassId == -1)
                    {
                        // In subtitle scan
                        completeWeight = e.FractionComplete * SubtitleScanCost;
                    }
                    else if (e.PassId == 1)
                    {
                        // First normal pass
                        completeWeight = SubtitleScanCost + e.FractionComplete;
                    }
                    else
                    {
                        // Second normal pass
                        completeWeight = SubtitleScanCost + 1 + e.FractionComplete;
                    }
                }


                double fractionComplete = completeWeight / totalWeight;
                this.PreviewPercentComplete = fractionComplete * 100;
            };
            this.encodeProxy.EncodeCompleted += (o, e) =>
            {
                DispatchUtilities.BeginInvoke(() =>
                {
                    this.EncodeState = PreviewEncodeState.NotEncoding;

                    if (this.encodeCancelled)
                    {
                        this.logger.Log("Cancelled preview clip generation");
                    }
                    else
                    {
                        if (e.Error)
                        {
                            this.logger.Log(PreviewRes.PreviewClipGenerationFailedTitle);
                            Utilities.MessageBox.Show(PreviewRes.PreviewClipGenerationFailedMessage);
                        }
                        else
                        {
                            var previewFileInfo = new FileInfo(this.previewFilePath);
                            this.logger.Log("Finished preview clip generation. Size: " + Utilities.FormatFileSize(previewFileInfo.Length));

                            this.PlayPreview();
                        }
                    }
                });
            };

            this.logger.Log("Generating preview clip");
            this.logger.Log("  Path: " + this.job.OutputPath);
            this.logger.Log("  Title: " + this.job.Title);
            this.logger.Log("  Preview #: " + this.SelectedPreview);

            this.encodeProxy.StartEncode(this.job, this.logger, true, this.SelectedPreview, this.PreviewSeconds, this.job.Length.TotalSeconds);
        }
Ejemplo n.º 10
0
        private void ProcessPreviewImageWork(object state)
        {
            PreviewImageJob imageJob;
            bool            workLeft = true;

            while (workLeft)
            {
                lock (this.imageSync)
                {
                    if (this.previewImageWorkQueue.Count == 0)
                    {
                        this.previewImageQueueProcessing = false;
                        return;
                    }

                    imageJob = this.previewImageWorkQueue.Dequeue();
                    while (imageJob.UpdateVersion < updateVersion)
                    {
                        if (this.previewImageWorkQueue.Count == 0)
                        {
                            this.previewImageQueueProcessing = false;
                            return;
                        }

                        imageJob = this.previewImageWorkQueue.Dequeue();
                    }
                }

                string       imagePath   = Path.Combine(Utilities.ImageCacheFolder, Process.GetCurrentProcess().Id.ToString(CultureInfo.InvariantCulture), imageJob.UpdateVersion.ToString(CultureInfo.InvariantCulture), imageJob.PreviewNumber + ".bmp");
                BitmapSource imageSource = null;

                // Check the disc cache for the image
                lock (imageJob.ImageFileSync)
                {
                    if (File.Exists(imagePath))
                    {
                        // When we read from disc cache the image is already transformed.
                        var bitmapImage = new BitmapImage();
                        bitmapImage.BeginInit();
                        bitmapImage.CacheOption = BitmapCacheOption.OnLoad;
                        bitmapImage.UriSource   = new Uri(imagePath);
                        bitmapImage.EndInit();
                        bitmapImage.Freeze();

                        imageSource = bitmapImage;
                    }
                }

                if (imageSource == null && !imageJob.ScanInstance.IsDisposed)
                {
                    // Make a HandBrake call to get the image
                    imageSource = imageJob.ScanInstance.GetPreview(imageJob.Profile.CreatePreviewSettings(imageJob.Title), imageJob.PreviewNumber);

                    // Transform the image as per rotation and reflection settings
                    VCProfile profile = imageJob.Profile;
                    if (profile.FlipHorizontal || profile.FlipVertical || profile.Rotation != VCPictureRotation.None)
                    {
                        imageSource = CreateTransformedBitmap(imageSource, profile);
                    }

                    // Start saving the image file in the background and continue to process the queue.
                    ThreadPool.QueueUserWorkItem(this.BackgroundFileSave, new SaveImageJob
                    {
                        PreviewNumber = imageJob.PreviewNumber,
                        UpdateVersion = imageJob.UpdateVersion,
                        FilePath      = imagePath,
                        Image         = imageSource,
                        ImageFileSync = imageJob.ImageFileSync
                    });
                }

                lock (this.imageSync)
                {
                    if (imageJob.UpdateVersion == updateVersion)
                    {
                        this.previewImageCache[imageJob.PreviewNumber] = imageSource;
                        if (this.SelectedPreview == imageJob.PreviewNumber)
                        {
                            DispatchUtilities.BeginInvoke(() =>
                            {
                                this.previewBitmapSource = imageSource;
                                this.RefreshFromBitmapImage();
                            });
                        }
                    }

                    if (this.previewImageWorkQueue.Count == 0)
                    {
                        workLeft = false;
                        this.previewImageQueueProcessing = false;
                    }
                }
            }
        }
Ejemplo n.º 11
0
 private void HandleDiscEvent(object sender, EventArrivedEventArgs e)
 {
     DispatchUtilities.BeginInvoke(() => this.mainViewModel.UpdateDriveCollection());
 }