// -------------------------------------------------------------------------------------------------------------------- // // This file is part of the HandBrake source code - It may be used under the terms of the GNU General Public License. // // // The Subtitles View Model // // -------------------------------------------------------------------------------------------------------------------- using System.IO; namespace HandBrakeWPF.ViewModels { using System.Collections.Generic; using System.Collections.Specialized; using System.ComponentModel; using System.ComponentModel.Composition; using System.Linq; using Caliburn.Micro; using HandBrake.ApplicationServices.Model; using HandBrake.ApplicationServices.Model.Encoding; using HandBrake.ApplicationServices.Parsing; using HandBrake.ApplicationServices.Services.Interfaces; using HandBrake.ApplicationServices.Utilities; using HandBrakeWPF.ViewModels.Interfaces; using Ookii.Dialogs.Wpf; /// /// The Subtitles View Model /// [Export(typeof(ISubtitlesViewModel))] public class SubtitlesViewModel : ViewModelBase, ISubtitlesViewModel { #region Constants and Fields /// /// Backing field for the source subtitle tracks. /// private IList sourceTracks; /// /// The Foreign Audio Search Track /// private readonly Subtitle ForeignAudioSearchTrack; #endregion #region Constructors and Destructors /// /// Initializes a new instance of the class. /// /// /// The window manager. /// /// /// The user Setting Service. /// public SubtitlesViewModel(IWindowManager windowManager, IUserSettingService userSettingService) { this.Task = new EncodeTask(); this.Langauges = LanguageUtilities.MapLanguages().Keys; this.CharacterCodes = CharCodesUtilities.GetCharacterCodes(); this.ForeignAudioSearchTrack = new Subtitle { SubtitleType = SubtitleType.ForeignAudioSearch, Language = "Foreign Audio Search (Bitmap)" }; this.SourceTracks = new List { this.ForeignAudioSearchTrack }; } #endregion #region Properties /// /// Gets or sets CharacterCodes. /// public IEnumerable CharacterCodes { get; set; } /// /// Gets or sets Langauges. /// public IEnumerable Langauges { get; set; } /// /// Gets or sets SourceTracks. /// public IList SourceTracks { get { return this.sourceTracks; } set { this.sourceTracks = value; this.NotifyOfPropertyChange(() => this.SourceTracks); } } /// /// Gets or sets Task. /// public EncodeTask Task { get; set; } #endregion #region Public Methods /// /// Add a new Track /// public void Add() { this.Add(null); } /// /// Automatic Subtitle Selection based on user preferences. /// public void AutomaticSubtitleSelection() { this.Task.SubtitleTracks.Clear(); // New DUB Settings int mode = this.UserSettingService.GetUserSetting(UserSettingConstants.DubModeSubtitle); switch (mode) { case 1: // Adding all remaining subtitle tracks this.AddAllRemaining(); break; case 2: // Adding only the first or preferred first subtitle track. this.Add(); break; case 3: // Selected Languages Only this.AddAllRemainingForSelectedLanguages(); break; case 4: // Prefered Only this.AddForPreferredLanaguages(true); break; case 5: // Prefered Only All this.AddForPreferredLanaguages(false); break; } // Add all closed captions if enabled. this.AddAllClosedCaptions(); } /// /// Import an SRT File. /// public void Import() { VistaOpenFileDialog dialog = new VistaOpenFileDialog { Filter = "SRT files (*.srt)|*.srt", CheckFileExists = true, Multiselect = true }; dialog.ShowDialog(); foreach (var srtFile in dialog.FileNames) { SubtitleTrack track = new SubtitleTrack { SrtFileName = Path.GetFileNameWithoutExtension(srtFile), SrtOffset = 0, SrtCharCode = "UTF-8", SrtLang = "English", SubtitleType = SubtitleType.SRT, SrtPath = srtFile }; this.Task.SubtitleTracks.Add(track); } } /// /// Remove a Track /// /// /// The track. /// public void Remove(SubtitleTrack track) { this.Task.SubtitleTracks.Remove(track); } /// /// Select the default subtitle track. /// /// /// The subtitle. /// public void SelectDefaultTrack(SubtitleTrack subtitle) { foreach (SubtitleTrack track in this.Task.SubtitleTracks) { if (track == subtitle) { continue; // Skip the track the user selected. } track.Default = false; } this.NotifyOfPropertyChange(() => this.Task); } /// /// Select the burned in track. /// /// /// The subtitle. /// public void SelectBurnedInTrack(SubtitleTrack subtitle) { foreach (SubtitleTrack track in this.Task.SubtitleTracks) { if (track == subtitle) { continue; // Skip the track the user selected. } track.Burned = false; } this.NotifyOfPropertyChange(() => this.Task); } #endregion #region Implemented Interfaces #region ITabInterface /// /// Setup this tab for the specified preset. /// /// /// The preset. /// /// /// The task. /// public void SetPreset(Preset preset, EncodeTask task) { // Note, We don't support Subtitles in presets yet. this.Task = task; this.NotifyOfPropertyChange(() => this.Task); } /// /// Update all the UI controls based on the encode task passed in. /// /// /// The task. /// public void UpdateTask(EncodeTask task) { this.Task = task; this.NotifyOfPropertyChange(() => this.Task.SubtitleTracks); this.NotifyOfPropertyChange(() => this.Task); } /// /// Setup this window for a new source /// /// /// The title. /// /// /// The preset. /// /// /// The task. /// public void SetSource(Title title, Preset preset, EncodeTask task) { this.SourceTracks.Clear(); this.SourceTracks.Add(ForeignAudioSearchTrack); foreach (Subtitle subtitle in title.Subtitles) { this.SourceTracks.Add(subtitle); } this.Task = task; this.NotifyOfPropertyChange(() => this.Task); this.AutomaticSubtitleSelection(); } #endregion #endregion #region Methods /// /// Add a subtitle track. /// The Source track is set based on the following order. If null, it will skip to the next option. /// 1. Passed in Subitle param /// 2. First preferred Subtitle from source /// 3. First subtitle from source. /// Will not add a subtitle if the source has none. /// /// /// The subtitle. Use null to add preferred, or first from source (based on user preference) /// private void Add(Subtitle subtitle) { string preferred = this.UserSettingService.GetUserSetting(UserSettingConstants.NativeLanguageForSubtitles); Subtitle source = subtitle ?? ((this.SourceTracks != null) ? (this.SourceTracks.FirstOrDefault(l => l.Language == preferred) ?? this.SourceTracks.FirstOrDefault(s => s.SubtitleType != SubtitleType.ForeignAudioSearch)) : null); if (source == null) { source = ForeignAudioSearchTrack; } SubtitleTrack track = new SubtitleTrack { SubtitleType = SubtitleType.VobSub, SourceTrack = source, }; this.Task.SubtitleTracks.Add(track); } /// /// Add all closed captions not already on the list. /// private void AddAllClosedCaptions() { if (this.UserSettingService.GetUserSetting(UserSettingConstants.UseClosedCaption)) { foreach ( Subtitle subtitle in this.SourceTitlesSubset(null).Where(s => s.SubtitleType == SubtitleType.CC)) { this.Add(subtitle); } } } /// /// Add all the remaining subtitle tracks. /// private void AddAllRemaining() { foreach (Subtitle subtitle in this.SourceTitlesSubset(null)) { this.Add(subtitle); } } /// /// Add all remaining tracks for the users preferred and selected languages /// private void AddAllRemainingForSelectedLanguages() { // Get a list of subtitle tracks that match the users lanaguages StringCollection userSelectedLanguages = this.UserSettingService.GetUserSetting(UserSettingConstants.SelectedLanguages); userSelectedLanguages.Add( this.UserSettingService.GetUserSetting(UserSettingConstants.NativeLanguageForSubtitles)); List availableTracks = this.SourceTracks.Where(subtitle => userSelectedLanguages.Contains(subtitle.Language)).ToList(); foreach (Subtitle subtitle in this.SourceTitlesSubset(availableTracks)) { this.Add(subtitle); } } /// /// Add all tracks for the preferred languages settings. /// /// /// The first only. /// private void AddForPreferredLanaguages(bool firstOnly) { string preferred = this.UserSettingService.GetUserSetting(UserSettingConstants.NativeLanguageForSubtitles); foreach (Subtitle subtitle in this.SourceTitlesSubset(null)) { if (subtitle.Language == preferred) { this.Add(subtitle); if (firstOnly) { break; } } } } /// /// Gets a list of Source subtitle tracks that are not currently used. /// /// /// The subtitles. (Optional). If null, works on the full source subtitle collection /// /// /// An IEnumerable collection of subtitles /// private IEnumerable SourceTitlesSubset(IEnumerable subtitles) { return subtitles != null ? subtitles.Where( subtitle => !this.Task.SubtitleTracks.Any(track => track.SourceTrack == subtitle)).ToList() : this.SourceTracks.Where( subtitle => !this.Task.SubtitleTracks.Any(track => track.SourceTrack == subtitle)).ToList(); } #endregion } }