diff --git a/FoliCon/Models/Constants/GlobalVariables.cs b/FoliCon/Models/Constants/GlobalVariables.cs index 0a6e0533..2639483c 100644 --- a/FoliCon/Models/Constants/GlobalVariables.cs +++ b/FoliCon/Models/Constants/GlobalVariables.cs @@ -5,8 +5,7 @@ namespace FoliCon.Models.Constants; internal static class GlobalVariables { - public static bool SkipAll; - + public static IconOverlay IconOverlayType() { return new PosterIconConfigViewModel().IconOverlay switch diff --git a/FoliCon/Modules/utils/FileUtils.cs b/FoliCon/Modules/utils/FileUtils.cs index c8ebf599..b53b007b 100644 --- a/FoliCon/Modules/utils/FileUtils.cs +++ b/FoliCon/Modules/utils/FileUtils.cs @@ -101,6 +101,10 @@ public static List GetFolderNames(string folderPath) return folderNames; } + public static string[] GetAllSubFolders(string folderPath) + { + return Directory.GetDirectories(folderPath); + } /// /// Get List of file in given folder. /// diff --git a/FoliCon/Modules/utils/IconUtils.cs b/FoliCon/Modules/utils/IconUtils.cs index c4634805..539a5ad5 100644 --- a/FoliCon/Modules/utils/IconUtils.cs +++ b/FoliCon/Modules/utils/IconUtils.cs @@ -32,9 +32,13 @@ public static int MakeIco(string iconMode, string selectedFolder, List + /// Looks up a localized string similar to Skip this and all remaining titles of {0}. + /// + public static string SkipThisPlaceholderParent { + get { + return ResourceManager.GetString("SkipThisPlaceholderParent", resourceCulture); + } + } + /// /// Looks up a localized string similar to Skip this title.. /// diff --git a/FoliCon/Properties/Langs/Lang.ar.resx b/FoliCon/Properties/Langs/Lang.ar.resx index 38712aae..3179f8a7 100644 --- a/FoliCon/Properties/Langs/Lang.ar.resx +++ b/FoliCon/Properties/Langs/Lang.ar.resx @@ -612,4 +612,7 @@ تثبيت بيئة تشغيل WebView2 + + تخطي هذا وكل العناوين المتبقية لـ {0} + \ No newline at end of file diff --git a/FoliCon/Properties/Langs/Lang.es.resx b/FoliCon/Properties/Langs/Lang.es.resx index 688a29c2..86eb9979 100644 --- a/FoliCon/Properties/Langs/Lang.es.resx +++ b/FoliCon/Properties/Langs/Lang.es.resx @@ -612,4 +612,7 @@ Esto ayuda a folicon a identificar los medios sin tener que elegir entre título Instalar Runtime de WebView2 + + Omitir este y todos los títulos restantes de {0} + \ No newline at end of file diff --git a/FoliCon/Properties/Langs/Lang.hi.resx b/FoliCon/Properties/Langs/Lang.hi.resx index 4a92b7fd..fffbc592 100644 --- a/FoliCon/Properties/Langs/Lang.hi.resx +++ b/FoliCon/Properties/Langs/Lang.hi.resx @@ -612,4 +612,7 @@ WebView2 Runtime इंस्टॉल करें + + इसे और {0} के बाकी मीडिया को छोड़ दे + \ No newline at end of file diff --git a/FoliCon/Properties/Langs/Lang.pt.resx b/FoliCon/Properties/Langs/Lang.pt.resx index b2a63f74..9f47409c 100644 --- a/FoliCon/Properties/Langs/Lang.pt.resx +++ b/FoliCon/Properties/Langs/Lang.pt.resx @@ -611,4 +611,7 @@ e renovar o cache dos Ícones? Instalar Runtime do WebView2 + + Ignorar este e todos os títulos restantes de {0} + \ No newline at end of file diff --git a/FoliCon/Properties/Langs/Lang.resx b/FoliCon/Properties/Langs/Lang.resx index ad9637d8..29bddedf 100644 --- a/FoliCon/Properties/Langs/Lang.resx +++ b/FoliCon/Properties/Langs/Lang.resx @@ -616,4 +616,7 @@ and refresh Icon Cache? Install WebView2 Runtime + + Skip this and all remaining titles of {0} + \ No newline at end of file diff --git a/FoliCon/Properties/Langs/Lang.ru.resx b/FoliCon/Properties/Langs/Lang.ru.resx index 773846dd..f6831af8 100644 --- a/FoliCon/Properties/Langs/Lang.ru.resx +++ b/FoliCon/Properties/Langs/Lang.ru.resx @@ -615,4 +615,7 @@ Установить исполняющую среду WebView2 + + Пропустить этот и все оставшиеся заголовки {0} + \ No newline at end of file diff --git a/FoliCon/ViewModels/MainWindowViewModel.cs b/FoliCon/ViewModels/MainWindowViewModel.cs index a8903848..0a901d78 100644 --- a/FoliCon/ViewModels/MainWindowViewModel.cs +++ b/FoliCon/ViewModels/MainWindowViewModel.cs @@ -391,120 +391,48 @@ private async Task ProcessPosterModeAsync() { Logger.Debug("Entered ProcessPosterModeAsync method"); IsMakeEnabled = false; - GlobalVariables.SkipAll = false; - foreach (var itemTitle in Fnames) + await ProcessPosterFolderAsync(SelectedFolder); + + StatusBarProperties.AppStatus = "Idle"; + StatusBarProperties.AppStatusAdditional = ""; + } + + private async Task ProcessPosterFolderAsync(string folderPath) + { + var folders = FileUtils.GetAllSubFolders(folderPath); + foreach (var subFolder in folders) + { + await ProcessPosterFolderAsync(subFolder); + } + var subfolderNames = FileUtils.GetFolderNames(folderPath); + foreach (var itemTitle in subfolderNames) { - var fullFolderPath = $@"{SelectedFolder}\{itemTitle}"; + var fullFolderPath = $@"{folderPath}\{itemTitle}"; Logger.Debug("Processing Folder: {FullFolderPath}", fullFolderPath); + var (response, parsedTitle, isPickedById, mediaType) = await PerformPreprocessing(itemTitle, fullFolderPath); + + var resultCount = CalculateResultCount(response, isPickedById); + Logger.Info("Search Result Count: {ResultCount}", resultCount); var dialogResult = false; - StatusBarProperties.AppStatus = "Searching"; - StatusBarProperties.AppStatusAdditional = itemTitle; - // TODO: Set cursor to WAIT. var isAutoPicked = false; - var parsedTitle = TitleCleaner.CleanAndParse(itemTitle); - var (id, mediaType) = FileUtils.ReadMediaInfo(fullFolderPath); - var isPickedById = false; - ResultResponse response; - if (id != null && mediaType != null) - { - Logger.Info("MediaInfo found for {ItemTitle}, mediaType: {MediaType}, id: {Id}", itemTitle, mediaType, id); - isPickedById = true; - response = mediaType == "Game" ? await _igdbObject.SearchGameByIdAsync(id) : await _tmdbObject.SearchByIdAsync(int.Parse(id), mediaType); - } - else - { - Logger.Info("MediaInfo not found for {ItemTitle}, Searching by Title", itemTitle); - response = SearchMode == "Game" - ? await _igdbObject.SearchGameAsync(parsedTitle.Title) - : DataUtils.ShouldUseParsedTitle(parsedTitle) - ? await _tmdbObject.SearchAsync(parsedTitle, SearchMode) - : await _tmdbObject.SearchAsync(parsedTitle.Title, SearchMode); - } - int resultCount = isPickedById ? response.Result != null ? 1 : 0 : SearchMode == "Game" ? response.Result.Length : response.Result.TotalResults; - Logger.Info("Search Result Count: {ResultCount}", resultCount); + var skipAll = false; switch (resultCount) { case 0: - Logger.Debug("No result found for {ItemTitle}, {Mode}", itemTitle, SearchMode); - MessageBox.Show(CustomMessageBox.Info(LangProvider.GetLang("NothingFoundFor").Format(itemTitle), - LangProvider.GetLang("NoResultFound"))); - _dialogService.ShowSearchResult(SearchMode, parsedTitle.Title, fullFolderPath, response, - _tmdbObject, _igdbObject, isPickedById, - r => - { - dialogResult = r.Result switch - { - ButtonResult.None => false, - ButtonResult.OK => true, - ButtonResult.Cancel => false, - _ => false - }; - }); + dialogResult = await ProcessNoResultCase(itemTitle, response, fullFolderPath, parsedTitle.Title, isPickedById); break; case 1 when !IsPosterWindowShown: { - Logger.Debug("One result found for {ItemTitle}, {Mode}, as always show poster window is not enabled, directly selecting", - itemTitle, SearchMode); - try - { - if (isPickedById ? mediaType == "Game" : SearchMode == "Game") - { - var result = response.Result[0]; - _igdbObject.ResultPicked(result, fullFolderPath); - } - else - { - var result = isPickedById - ? response.Result - : response.Result.Results[0]; - _tmdbObject.ResultPicked(result, response.MediaType, - fullFolderPath, "", isPickedById); - } - - isAutoPicked = true; - } - catch (Exception ex) - { - Logger.ForErrorEvent().Message("ProcessPosterModeAsync: Exception Occurred. message: {Message}", ex.Message) - .Exception(ex).Log(); - if (ex.Message == "NoPoster") - { - MessageBox.Show(CustomMessageBox.Warning(LangProvider.GetLang("NoPosterFound"), itemTitle)); - } -#if DEBUG - MessageBox.Show(CustomMessageBox.Warning(ex.Message, LangProvider.GetLang("ExceptionOccurred"))); -#endif - isAutoPicked = false; - } - + isAutoPicked = ProcessSingleResultCase(itemTitle, response, fullFolderPath, isPickedById, mediaType); break; } default: { if (resultCount >= 1) { - if (IsPosterWindowShown || !IsSkipAmbiguous) - { - Logger.Debug("More than one result found for {ItemTitle}, {Mode}," + - "always show poster window: {IsPosterWindowShown}, Skip ambigous titles: {IsSkipAmbiguous}," + - " showing poster window", itemTitle, SearchMode, IsPosterWindowShown, IsSkipAmbiguous); - - _dialogService.ShowSearchResult(SearchMode, parsedTitle.Title, fullFolderPath, - response, _tmdbObject, _igdbObject, isPickedById, - r => - { - dialogResult = r.Result switch - { - ButtonResult.None => false, - ButtonResult.OK => true, - ButtonResult.Cancel => false, - _ => false - }; - }); - } + (dialogResult, skipAll) = await ProcessMultipleResultCase(itemTitle, response, fullFolderPath, parsedTitle.Title, isPickedById); } - break; } } @@ -520,15 +448,141 @@ private async Task ProcessPosterModeAsync() // TODO: Set cursor back to arrow here } StatusBarProperties.ProcessedFolder++; - if (!GlobalVariables.SkipAll) continue; + if (!skipAll) + { + continue; + } + Logger.Debug("Skip All selected, breaking loop"); break; } + } - StatusBarProperties.AppStatus = "Idle"; - StatusBarProperties.AppStatusAdditional = ""; + private async Task<(ResultResponse response, ParsedTitle parsedTitle, bool isPickedById, string mediaType)> PerformPreprocessing(string itemTitle, string fullFolderPath) + { + StatusBarProperties.AppStatus = "Searching"; + StatusBarProperties.AppStatusAdditional = itemTitle; + var parsedTitle = TitleCleaner.CleanAndParse(itemTitle); + var (id, mediaType) = FileUtils.ReadMediaInfo(fullFolderPath); + var isPickedById = false; + ResultResponse response; + if (id != null && mediaType != null) + { + Logger.Info("MediaInfo found for {ItemTitle}, mediaType: {MediaType}, id: {Id}", itemTitle, mediaType, id); + isPickedById = true; + response = mediaType == "Game" ? await _igdbObject.SearchGameByIdAsync(id) : await _tmdbObject.SearchByIdAsync(int.Parse(id), mediaType); + } + else + { + Logger.Info("MediaInfo not found for {ItemTitle}, Searching by Title", itemTitle); + response = SearchMode == "Game" + ? await _igdbObject.SearchGameAsync(parsedTitle.Title) + : DataUtils.ShouldUseParsedTitle(parsedTitle) + ? await _tmdbObject.SearchAsync(parsedTitle, SearchMode) + : await _tmdbObject.SearchAsync(parsedTitle.Title, SearchMode); + } + + return (response, parsedTitle, isPickedById, mediaType); + } + + private int CalculateResultCount(ResultResponse response, bool isPickedById) + { + return isPickedById ? response.Result != null ? 1 : 0 : + SearchMode == "Game" ? response.Result.Length : response.Result.TotalResults; + } + + private async Task ProcessNoResultCase(string itemTitle, ResultResponse response, string fullFolderPath, string parsedTitle, bool isPickedById) + { + Logger.Debug("No result found for {ItemTitle}, {Mode}", itemTitle, SearchMode); + MessageBox.Show(CustomMessageBox.Info(LangProvider.GetLang("NothingFoundFor").Format(itemTitle), + LangProvider.GetLang("NoResultFound"))); + + var taskCompletionSource = new TaskCompletionSource(); + + _dialogService.ShowSearchResult(SearchMode, parsedTitle, fullFolderPath, response, + _tmdbObject, _igdbObject, isPickedById, + r => + { + var dialogResult = r.Result switch + { + ButtonResult.None => false, + ButtonResult.OK => true, + ButtonResult.Cancel => false, + _ => false + }; + taskCompletionSource.SetResult(dialogResult); + }); + return await taskCompletionSource.Task; + } + + private bool ProcessSingleResultCase(string itemTitle, ResultResponse response, string fullFolderPath, bool isPickedById, string mediaType) + { + bool isAutoPicked; + Logger.Debug("One result found for {ItemTitle}, {Mode}, as always show poster window is not enabled, directly selecting", + itemTitle, SearchMode); + try + { + if (isPickedById ? mediaType == "Game" : SearchMode == "Game") + { + var result = response.Result[0]; + _igdbObject.ResultPicked(result, fullFolderPath); + } + else + { + var result = isPickedById + ? response.Result + : response.Result.Results[0]; + _tmdbObject.ResultPicked(result, response.MediaType, + fullFolderPath, "", isPickedById); + } + + isAutoPicked = true; + } + catch (Exception ex) + { + Logger.ForErrorEvent().Message("ProcessPosterModeAsync: Exception Occurred. message: {Message}", ex.Message) + .Exception(ex).Log(); + if (ex.Message == "NoPoster") + { + MessageBox.Show(CustomMessageBox.Warning(LangProvider.GetLang("NoPosterFound"), itemTitle)); + } +#if DEBUG + MessageBox.Show(CustomMessageBox.Warning(ex.Message, LangProvider.GetLang("ExceptionOccurred"))); +#endif + isAutoPicked = false; + } + return isAutoPicked; } + private async Task<(bool dialogResult, bool skipAll)> ProcessMultipleResultCase(string itemTitle, ResultResponse response, string fullFolderPath, string parsedTitle, bool isPickedById) + { + var taskCompletionSource = new TaskCompletionSource<(bool dialogResult, bool skipAll)>(); + if (!IsPosterWindowShown && IsSkipAmbiguous) + { + return await taskCompletionSource.Task; + } + + Logger.Debug("More than one result found for {ItemTitle}, {Mode}," + + "always show poster window: {IsPosterWindowShown}, Skip ambigous titles: {IsSkipAmbiguous}," + + " showing poster window", itemTitle, SearchMode, IsPosterWindowShown, IsSkipAmbiguous); + + _dialogService.ShowSearchResult(SearchMode, parsedTitle, fullFolderPath, + response, _tmdbObject, _igdbObject, isPickedById, + r => + { + var dialogResult = r.Result switch + { + ButtonResult.None => false, + ButtonResult.OK => true, + ButtonResult.Cancel => false, + _ => false + }; + r.Parameters.TryGetValue("skipAll", out var skipAll); + taskCompletionSource.SetResult((dialogResult, skipAll)); + }); + return await taskCompletionSource.Task; + } + private void ProcessProfessionalMode() { Logger.Debug("Entered ProcessProfessionalMode method"); diff --git a/FoliCon/ViewModels/SearchResultViewModel.cs b/FoliCon/ViewModels/SearchResultViewModel.cs index 9e359dc8..a934c3b6 100644 --- a/FoliCon/ViewModels/SearchResultViewModel.cs +++ b/FoliCon/ViewModels/SearchResultViewModel.cs @@ -23,6 +23,7 @@ public class SearchResultViewModel : BindableBase, IDialogAware private string _searchMode; private ListViewData _resultListViewData; private string _searchAgainTitle; + private string _skipAllText = LangProvider.GetLang("SkipThisPlaceholder"); private List _fileList; private ResultResponse _searchResult; private string _fullFolderPath; @@ -81,6 +82,12 @@ public string SearchAgainTitle set => SetProperty(ref _searchAgainTitle, value); } + public string SkipAllText + { + get => _skipAllText; + set => SetProperty(ref _skipAllText, value); + } + public List FileList { get => _fileList; @@ -128,12 +135,16 @@ public SearchResultViewModel(IDialogService dialogService) ResetPosterCommand = new DelegateCommand(ResetPoster); SkipAllCommand = new DelegateCommand(delegate { - GlobalVariables.SkipAll = true; - CloseDialog("false"); + CloseDialog("false", true); }); } protected virtual void CloseDialog(string parameter) + { + CloseDialog(parameter, false); + } + + protected virtual void CloseDialog(string parameter, bool skipAll) { var result = parameter?.ToLower(CultureInfo.InvariantCulture) switch { @@ -141,8 +152,11 @@ protected virtual void CloseDialog(string parameter) "false" => ButtonResult.Cancel, _ => ButtonResult.None }; - - RaiseRequestClose(new DialogResult(result)); + var parameters = new DialogParameters + { + { "skipAll", skipAll } + }; + RaiseRequestClose(new DialogResult(result, parameters)); } public virtual void RaiseRequestClose(IDialogResult dialogResult) @@ -168,6 +182,12 @@ public virtual void OnDialogOpened(IDialogParameters parameters) _igdbObject = parameters.GetValue("igdbObject"); _fullFolderPath = parameters.GetValue("folderpath"); _isPickedById = parameters.GetValue("isPickedById"); + var parent = Directory.GetParent(_fullFolderPath); + if (parent != null) + { + SkipAllText = LangProvider.GetLang("SkipThisPlaceholderParent").Format(parent.Name); + } + LoadData(SearchTitle); SearchAgainTitle = SearchTitle; FileList = FileUtils.GetFileNamesFromFolder(_fullFolderPath); diff --git a/FoliCon/Views/SearchResult.xaml b/FoliCon/Views/SearchResult.xaml index 3186130d..bee3a957 100644 --- a/FoliCon/Views/SearchResult.xaml +++ b/FoliCon/Views/SearchResult.xaml @@ -100,7 +100,7 @@