From 8893a2538104857637b8d16a078aa416bd9bdfda Mon Sep 17 00:00:00 2001 From: Dinesh Solanki <15937452+dineshsolanki@users.noreply.github.com> Date: Thu, 21 Mar 2024 23:34:44 +0530 Subject: [PATCH 1/5] Refactor PosterMode processing code to including nested folder such as for the case of different parts of a movie collection Known issue - Parent folder is not processed --- FoliCon/Modules/utils/FileUtils.cs | 5 + FoliCon/Modules/utils/IconUtils.cs | 10 +- FoliCon/ViewModels/MainWindowViewModel.cs | 238 +++++++++++++--------- 3 files changed, 153 insertions(+), 100 deletions(-) diff --git a/FoliCon/Modules/utils/FileUtils.cs b/FoliCon/Modules/utils/FileUtils.cs index c8ebf59..30ce50c 100644 --- a/FoliCon/Modules/utils/FileUtils.cs +++ b/FoliCon/Modules/utils/FileUtils.cs @@ -101,6 +101,11 @@ public static List GetFolderNames(string folderPath) return folderNames; } + public static List GetAllSubFolders(string folderPath) + { + DirectoryInfo di = new(folderPath); + return di.GetDirectories().Select(info => info.FullName).ToList(); + } /// /// Get List of file in given folder. /// diff --git a/FoliCon/Modules/utils/IconUtils.cs b/FoliCon/Modules/utils/IconUtils.cs index c463480..539a5ad 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 - { - 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 = await ProcessMultipleResultCase(itemTitle, response, fullFolderPath, parsedTitle.Title, isPickedById); } - break; } } @@ -524,11 +451,128 @@ private async Task ProcessPosterModeAsync() 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 ProcessMultipleResultCase(string itemTitle, ResultResponse response, string fullFolderPath, string parsedTitle, bool isPickedById) + { + var taskCompletionSource = new TaskCompletionSource(); + 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 + }; + taskCompletionSource.SetResult(dialogResult); + }); + return await taskCompletionSource.Task; + } + private void ProcessProfessionalMode() { Logger.Debug("Entered ProcessProfessionalMode method"); From 54c29f0c1db8a0895afae48a546c4a426f775958 Mon Sep 17 00:00:00 2001 From: Dinesh Solanki <15937452+dineshsolanki@users.noreply.github.com> Date: Fri, 22 Mar 2024 00:22:54 +0530 Subject: [PATCH 2/5] chore: Refactor dialog skipping logic Implement parameterized CloseDialog method to incorporate skipAll logic, and remove GlobalVariables.SkipAll flag usage. Dialog skipping now relies on a passed parameter rather than a global variable, this would help in skipping only the subfolders of parent only in case of nested folders, and also is a step toward eliminating global variables. --- FoliCon/Models/Constants/GlobalVariables.cs | 3 +-- FoliCon/ViewModels/MainWindowViewModel.cs | 16 +++++++++------- FoliCon/ViewModels/SearchResultViewModel.cs | 15 +++++++++++---- 3 files changed, 21 insertions(+), 13 deletions(-) diff --git a/FoliCon/Models/Constants/GlobalVariables.cs b/FoliCon/Models/Constants/GlobalVariables.cs index 0a6e053..2639483 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/ViewModels/MainWindowViewModel.cs b/FoliCon/ViewModels/MainWindowViewModel.cs index 9060ab9..36a9121 100644 --- a/FoliCon/ViewModels/MainWindowViewModel.cs +++ b/FoliCon/ViewModels/MainWindowViewModel.cs @@ -391,7 +391,6 @@ private async Task ProcessPosterModeAsync() { Logger.Debug("Entered ProcessPosterModeAsync method"); IsMakeEnabled = false; - GlobalVariables.SkipAll = false; await ProcessPosterFolderAsync(SelectedFolder); StatusBarProperties.AppStatus = "Idle"; @@ -400,7 +399,8 @@ private async Task ProcessPosterModeAsync() private async Task ProcessPosterFolderAsync(string folderPath) { - foreach (var subFolder in FileUtils.GetAllSubFolders(folderPath)) + var folders = FileUtils.GetAllSubFolders(folderPath); + foreach (var subFolder in folders) { await ProcessPosterFolderAsync(subFolder); } @@ -416,6 +416,7 @@ private async Task ProcessPosterFolderAsync(string folderPath) Logger.Info("Search Result Count: {ResultCount}", resultCount); var dialogResult = false; var isAutoPicked = false; + var skipAll = false; switch (resultCount) { case 0: @@ -430,7 +431,7 @@ private async Task ProcessPosterFolderAsync(string folderPath) { if (resultCount >= 1) { - dialogResult = await ProcessMultipleResultCase(itemTitle, response, fullFolderPath, parsedTitle.Title, isPickedById); + (dialogResult, skipAll) = await ProcessMultipleResultCase(itemTitle, response, fullFolderPath, parsedTitle.Title, isPickedById); } break; } @@ -447,7 +448,7 @@ private async Task ProcessPosterFolderAsync(string folderPath) // TODO: Set cursor back to arrow here } StatusBarProperties.ProcessedFolder++; - if (!GlobalVariables.SkipAll) continue; + if (!skipAll) continue; Logger.Debug("Skip All selected, breaking loop"); break; } @@ -549,9 +550,9 @@ private bool ProcessSingleResultCase(string itemTitle, ResultResponse response, return isAutoPicked; } - private async Task ProcessMultipleResultCase(string itemTitle, ResultResponse response, string fullFolderPath, string parsedTitle, bool isPickedById) + private async Task<(bool dialogResult, bool skipAll)> ProcessMultipleResultCase(string itemTitle, ResultResponse response, string fullFolderPath, string parsedTitle, bool isPickedById) { - var taskCompletionSource = new TaskCompletionSource(); + 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}," + @@ -568,7 +569,8 @@ private async Task ProcessMultipleResultCase(string itemTitle, ResultRespo ButtonResult.Cancel => false, _ => false }; - taskCompletionSource.SetResult(dialogResult); + r.Parameters.TryGetValue("skipAll", out var skipAll); + taskCompletionSource.SetResult((dialogResult, skipAll)); }); return await taskCompletionSource.Task; } diff --git a/FoliCon/ViewModels/SearchResultViewModel.cs b/FoliCon/ViewModels/SearchResultViewModel.cs index 9e359dc..0a189ad 100644 --- a/FoliCon/ViewModels/SearchResultViewModel.cs +++ b/FoliCon/ViewModels/SearchResultViewModel.cs @@ -128,12 +128,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 +145,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) From 97631308962b2b437cfcf654f8502de11e2af007 Mon Sep 17 00:00:00 2001 From: Dinesh Solanki <15937452+dineshsolanki@users.noreply.github.com> Date: Fri, 22 Mar 2024 00:25:09 +0530 Subject: [PATCH 3/5] fix: skip of all folders instead of folders of parent only Added text and translations to skip all remaining titles for a specific parent directory (part of feature #192). The SkipAllText property is now dynamically set based on the parent folder name in the SearchResultViewModel. --- FoliCon/Properties/Langs/Lang.Designer.cs | 9 +++++++++ FoliCon/Properties/Langs/Lang.ar.resx | 3 +++ FoliCon/Properties/Langs/Lang.es.resx | 3 +++ FoliCon/Properties/Langs/Lang.hi.resx | 3 +++ FoliCon/Properties/Langs/Lang.pt.resx | 3 +++ FoliCon/Properties/Langs/Lang.resx | 3 +++ FoliCon/Properties/Langs/Lang.ru.resx | 3 +++ FoliCon/ViewModels/SearchResultViewModel.cs | 9 +++++++++ FoliCon/Views/SearchResult.xaml | 2 +- 9 files changed, 37 insertions(+), 1 deletion(-) diff --git a/FoliCon/Properties/Langs/Lang.Designer.cs b/FoliCon/Properties/Langs/Lang.Designer.cs index d632241..8a27916 100644 --- a/FoliCon/Properties/Langs/Lang.Designer.cs +++ b/FoliCon/Properties/Langs/Lang.Designer.cs @@ -1310,6 +1310,15 @@ public static string SkipThisPlaceholder { } } + /// + /// 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 38712aa..3179f8a 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 688a29c..86eb997 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 4a92b7f..fffbc59 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 b2a63f7..9f47409 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 ad9637d..29bdded 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 773846d..f6831af 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/SearchResultViewModel.cs b/FoliCon/ViewModels/SearchResultViewModel.cs index 0a189ad..23520ea 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; @@ -175,6 +182,8 @@ 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 3186130..bee3a95 100644 --- a/FoliCon/Views/SearchResult.xaml +++ b/FoliCon/Views/SearchResult.xaml @@ -100,7 +100,7 @@