diff --git a/Assets/Main_menu.png b/Assets/Main_menu.png index 779c74ab..eb901425 100644 Binary files a/Assets/Main_menu.png and b/Assets/Main_menu.png differ diff --git a/CHANGELOG.md b/CHANGELOG.md index 74e80b1d..b4e0a489 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,16 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] +## [0.1.180] - 2022-12-13 +### Added +- Info menu +- Download progress +### Changed +- Connect menu +- Settings menu +- Collect info after set user name +- Try catch exceptions + ## [0.1.150] - 2022-12-10 ### Added - MenuHelper into TgDownloaderConsole diff --git a/README.md b/README.md index ee37b1d2..d50babc4 100644 --- a/README.md +++ b/README.md @@ -19,6 +19,12 @@ Download all the files from the channel you are a member of from Telegram. - Fill out the form to register a new Telegram app - Copy the values of the "App api_id" and "App api_hash" fields +## Quick start +- Connect TG client, enter requred fields +- Get info about your dialogs (optional) +- Fill the settings +- Download files + ## Screenshots ![](Assets/Main_menu.png?raw=true) diff --git a/TgDownloaderConsole/GlobalUsings.cs b/TgDownloaderConsole/GlobalUsings.cs index 2b5db42f..9272a3b6 100644 --- a/TgDownloaderConsole/GlobalUsings.cs +++ b/TgDownloaderConsole/GlobalUsings.cs @@ -8,5 +8,4 @@ global using TgDownloaderConsole.Helpers; global using TgDownloaderCore.Enums; global using TgDownloaderCore.Helpers; -global using TgDownloaderCore.Locales; global using TL; diff --git a/TgDownloaderConsole/Helpers/MenuHelper.cs b/TgDownloaderConsole/Helpers/MenuHelper.cs index 22f3f8ce..29d6b22b 100644 --- a/TgDownloaderConsole/Helpers/MenuHelper.cs +++ b/TgDownloaderConsole/Helpers/MenuHelper.cs @@ -18,19 +18,6 @@ internal class MenuHelper internal static TgClientHelper TgClient => TgClientHelper.Instance; internal static Style StyleMain => new(Color.White, null, Decoration.Bold | Decoration.Conceal | Decoration.Italic); - internal long SourceFileSize { get; set; } - internal long SourceFileRead { get; set; } - internal double SourceFileProgress - { - get - { - if (SourceFileSize == 0) - return 0; - return (double)(SourceFileRead * 100) / SourceFileSize; - } - } - internal TgMenu MenuItem { get; set; } = TgMenu.Exit; - #endregion #region Public and internal methods @@ -46,7 +33,7 @@ internal static string GetAppVersion() internal void ShowTable(string title) { AnsiConsole.Clear(); - AnsiConsole.Write(new FigletText(Locale.Info.AppTitle).Alignment(Justify.Center).Color(Color.Yellow)); + AnsiConsole.Write(new FigletText(Locale.AppTitle).Alignment(Justify.Center).Color(Color.Yellow)); Table table = new() { ShowHeaders = true, @@ -66,130 +53,116 @@ internal void FillTableColumns(Table table) if (table.Columns.Count > 0) return; table.AddColumn(new TableColumn( - new Markup(Locale.Info.AppName, StyleMain)) { Width = 20 }.LeftAligned()); + new Markup(Locale.AppName, StyleMain)) { Width = 20 }.LeftAligned()); table.AddColumn(new TableColumn( - new Markup(Locale.Info.AppValue, StyleMain)) { Width = 80 }.LeftAligned()); + new Markup(Locale.AppValue, StyleMain)) { Width = 80 }.LeftAligned()); } internal void FillTableRows(Table table) { if (table.Rows.Count > 0) table.Rows.Clear(); - table.AddRow(new Markup(Locale.InfoMessage(Locale.Info.AppVersion)), new Markup($@"v{GetAppVersion()}")); + table.AddRow(new Markup(Locale.InfoMessage(Locale.AppVersion)), new Markup($@"v{GetAppVersion()}")); // TG client info. if (!TgClient.IsConnected) { - table.AddRow(new Markup(Locale.WarningMessage(Locale.Info.TgClientUserName)), - new Markup(Locale.Warning.TgSettingsNotSet)); - table.AddRow(new Markup(Locale.WarningMessage(Locale.Info.TgClientUserId)), - new Markup(Locale.Warning.TgSettingsNotSet)); - table.AddRow(new Markup(Locale.WarningMessage(Locale.Info.TgClientUserIsActive)), - new Markup(Locale.Warning.TgSettingsNotSet)); - table.AddRow(new Markup(Locale.WarningMessage(Locale.Info.TgClientUserStatus)), - new Markup(Locale.Warning.TgSettingsNotSet)); + table.AddRow(new Markup(Locale.WarningMessage(Locale.TgClientUserName)), + new Markup(Locale.TgSettingsNotSet)); + table.AddRow(new Markup(Locale.WarningMessage(Locale.TgClientUserId)), + new Markup(Locale.TgSettingsNotSet)); + table.AddRow(new Markup(Locale.WarningMessage(Locale.TgClientUserIsActive)), + new Markup(Locale.TgSettingsNotSet)); + table.AddRow(new Markup(Locale.WarningMessage(Locale.TgClientUserStatus)), + new Markup(Locale.TgSettingsNotSet)); } else { User user = TgClient.MySelfUser; - table.AddRow(new Markup(Locale.InfoMessage(Locale.Info.TgClientUserName)), + table.AddRow(new Markup(Locale.InfoMessage(Locale.TgClientUserName)), new Markup(user.username)); - table.AddRow(new Markup(Locale.InfoMessage(Locale.Info.TgClientUserId)), + table.AddRow(new Markup(Locale.InfoMessage(Locale.TgClientUserId)), new Markup(user.id.ToString())); - table.AddRow(new Markup(Locale.InfoMessage(Locale.Info.TgClientUserIsActive)), + table.AddRow(new Markup(Locale.InfoMessage(Locale.TgClientUserIsActive)), new Markup(user.IsActive.ToString())); - table.AddRow(new Markup(Locale.InfoMessage(Locale.Info.TgClientUserStatus)), + table.AddRow(new Markup(Locale.InfoMessage(Locale.TgClientUserStatus)), new Markup(user.status.ToString() ?? "")); } // TG source user name. if (string.IsNullOrEmpty(TgClient.TgSettings.SourceUserName)) - table.AddRow(new Markup(Locale.WarningMessage(Locale.Info.TgSettingsSourceUserName)), - new Markup(Locale.Warning.TgSettingsNotSet)); + table.AddRow(new Markup(Locale.WarningMessage(Locale.TgSettingsSourceUserName)), + new Markup(Locale.TgSettingsNotSet)); else - table.AddRow(new Markup(Locale.InfoMessage(Locale.Info.TgSettingsSourceUserName)), + table.AddRow(new Markup(Locale.InfoMessage(Locale.TgSettingsSourceUserName)), new Markup(TgClient.TgSettings.SourceUserName)); + // TG messages count. + if (TgClient.TgSettings.MessageCount < 0) + table.AddRow(new Markup(Locale.WarningMessage(Locale.TgSettingsMessageCount)), + new Markup(Locale.TgSettingsNotSet)); + else + table.AddRow(new Markup(Locale.InfoMessage(Locale.TgSettingsMessageCount)), + new Markup(TgClient.TgSettings.MessageCount.ToString())); + // Dest dir. if (string.IsNullOrEmpty(TgClient.TgSettings.DestDirectory)) - table.AddRow(new Markup(Locale.WarningMessage(Locale.Info.TgSettingsDestDirectory)), - new Markup(Locale.Warning.TgSettingsNotSet)); + table.AddRow(new Markup(Locale.WarningMessage(Locale.TgSettingsDestDirectory)), + new Markup(Locale.TgSettingsNotSet)); else { if (!Directory.Exists(TgClient.TgSettings.DestDirectory)) - table.AddRow(new Markup(Locale.WarningMessage(Locale.Info.TgSettingsDestDirectory)), - new Markup(Locale.Warning.DirIsNotExists)); + table.AddRow(new Markup(Locale.WarningMessage(Locale.TgSettingsDestDirectory)), + new Markup(Locale.DirIsNotExists)); else - table.AddRow(new Markup(Locale.InfoMessage(Locale.Info.TgSettingsDestDirectory)), + table.AddRow(new Markup(Locale.InfoMessage(Locale.TgSettingsDestDirectory)), new Markup(TgClient.TgSettings.DestDirectory)); } // TG start ID. - if (TgClient.TgSettings.MessageStartId < 0) - table.AddRow(new Markup(Locale.WarningMessage(Locale.Info.TgSettingsMessageStartId)), - new Markup(Locale.Warning.TgSettingsNotSet)); + if (TgClient.TgSettings.MessageCurrentId < 0) + table.AddRow(new Markup(Locale.WarningMessage(Locale.TgSettingsMessageStartId)), + new Markup(Locale.TgSettingsNotSet)); else - table.AddRow(new Markup(Locale.InfoMessage(Locale.Info.TgSettingsMessageStartId)), - new Markup(TgClient.TgSettings.MessageStartId.ToString())); - - // TG messages count. - if (TgClient.TgSettings.MessageCount < 0) - table.AddRow(new Markup(Locale.WarningMessage(Locale.Info.TgSettingsMessageCount)), - new Markup(Locale.Warning.TgSettingsNotSet)); - else - table.AddRow(new Markup(Locale.InfoMessage(Locale.Info.TgSettingsMessageCount)), - new Markup(TgClient.TgSettings.MessageCount.ToString())); - - // TG messages max count. - if (TgClient.TgSettings.MessageMaxCount < 0) - table.AddRow(new Markup(Locale.WarningMessage(Locale.Info.TgSettingsMessageMaxCount)), - new Markup(Locale.Warning.TgSettingsNotSet)); - else - table.AddRow(new Markup(Locale.InfoMessage(Locale.Info.TgSettingsMessageMaxCount)), - new Markup(TgClient.TgSettings.MessageMaxCount.ToString())); - } - - internal string GetTableRowsSize(long value) - { - if (value > 0) - { - if (value < 1024) - return $"{value:##0.000} B"; - if (value < 1024 * 1024) - return $"{(double)value / 1024:##0.000} KB"; - return value < 1024 * 1024 * 1024 - ? $"{(double)value / 1024L / 1024:##0.000} MB" - : $"{(double)value / 1024L / 1024L / 1024:##0.000} GB"; - } - return "0 B"; + table.AddRow(new Markup(Locale.InfoMessage(Locale.TgSettingsMessageStartId)), + new Markup(TgClient.TgSettings.MessageCurrentId.ToString())); } - internal void SetOptionsSetupTg() + internal TgMenuSettings SetOptionsSetupTg() { - string subMenu = AnsiConsole.Prompt( + string menu = AnsiConsole.Prompt( new SelectionPrompt() - .Title(Locale.Info.MenuSwitchNumber) - .PageSize(6) - .MoreChoicesText(Locale.Info.MoveUpDown) + .Title(Locale.MenuSwitchNumber) + .PageSize(4) + .MoreChoicesText(Locale.MoveUpDown) .AddChoices( "Return", "Setup user name", "Setup download folder", - "Setup message start ID", - "Setup messages count")); - MenuItem = subMenu switch + "Setup message current ID")); + return menu switch { - "Return" => TgMenu.Return, - "Setup user name" => TgMenu.SetTgSourceUsername, - "Setup download folder" => TgMenu.SetTgDestDirectory, - "Setup message start ID" => TgMenu.SetTgMessageStartId, - "Setup messages count" => TgMenu.SetTgMessageCount, - _ => MenuItem + "Setup user name" => TgMenuSettings.SourceUsername, + "Setup download folder" => TgMenuSettings.DestDirectory, + "Setup message current ID" => TgMenuSettings.MessageCurrentId, + _ => TgMenuSettings.Return }; } - internal string GetStatusInfo(Stopwatch sw) => - $"{sw.Elapsed} | {SourceFileProgress:##0.000} % | {GetTableRowsSize(SourceFileRead)} |"; + internal double CalcSourceProgress(long count, long current) => + count == 0 ? 0 : (double)(current * 100) / count; + + private string GetLongString(long current) => current > 999 ? $"{current:### ###}" : $"{current:###}"; + + public string GetStatus(Stopwatch sw, long count, long current) => + count == 0 && current == 0 + ? $"{sw.Elapsed} | " + : $"{sw.Elapsed} | {CalcSourceProgress(count, current):#00.00} % | {GetLongString(current)}/{GetLongString(count)}"; + + public string GetStatus(long count, long current) => + count == 0 && current == 0 + ? string.Empty + : $"{CalcSourceProgress(count, current):#00.00} % | {GetLongString(current)}/{GetLongString(count)}"; public bool CheckTgSettings() => TgClient.IsConnected && diff --git a/TgDownloaderConsole/Program.cs b/TgDownloaderConsole/Program.cs index 85f18c12..6cb9ff16 100644 --- a/TgDownloaderConsole/Program.cs +++ b/TgDownloaderConsole/Program.cs @@ -6,46 +6,50 @@ LogHelper log = LogHelper.Instance; MenuHelper menu = MenuHelper.Instance; TgClientHelper tgClient = TgClientHelper.Instance; +StatusContext globalStatusContext = null; SetLog(); +TgMenu menuMain = TgMenu.Exit; do { try { - menu.ShowTable(""); - menu.MenuItem = TgMenu.Return; - string mainMenu = AnsiConsole.Prompt( + menu.ShowTable(locale.AppMainMenu); + string menuAsk = AnsiConsole.Prompt( new SelectionPrompt() - .Title(locale.Info.MenuSwitchNumber) - .PageSize(6) - .MoreChoicesText(locale.Info.MoveUpDown) - .AddChoices(locale.Info.MenuMain)); - switch (mainMenu) + .Title(locale.MenuSwitchNumber) + .PageSize(10) + .MoreChoicesText(locale.MoveUpDown) + .AddChoices(locale.MenuMain)); + switch (menuAsk) { - case "Exit": - menu.MenuItem = TgMenu.Exit; - break; case "Connect": + menuMain = TgMenu.Connect; ConnectTgClient(); break; + case "Info": + menuMain = TgMenu.Info; + GetTgInfo(); + break; case "Settings": + menuMain = TgMenu.Settings; SetupTgSettings(); break; case "Download files": - menu.MenuItem = TgMenu.DownloadFiles; + menuMain = TgMenu.DownloadFiles; RunMenuJob(DownloadFiles); break; } } catch (Exception ex) { - log.MarkupLineStamp(locale.Info.StatusException + log.GetMarkupString(ex.Message)); + log.MarkupLineStamp(locale.StatusException + log.GetMarkupString(ex.Message)); if (ex.InnerException is not null) - log.MarkupLineStamp(locale.Info.StatusInnerException + log.GetMarkupString(ex.InnerException.Message)); - menu.MenuItem = TgMenu.Exit; + log.MarkupLineStamp(locale.StatusInnerException + log.GetMarkupString(ex.InnerException.Message)); + menuMain = TgMenu.Exit; } -} while (menu.MenuItem is not TgMenu.Exit); +} while (menuMain is not TgMenu.Exit); void SetLog() { @@ -58,65 +62,100 @@ void SetLog() void SetupTgSettings() { - menu.ShowTable(locale.Info.MenuSetupTg); - menu.SetOptionsSetupTg(); - - switch (menu.MenuItem) + TgMenuSettings menuSettings; + do { - case TgMenu.SetTgSourceUsername: - tgClient.TgSettings.SetSourceUserName(); - break; - case TgMenu.SetTgDestDirectory: - tgClient.TgSettings.SetDestDirectory(); - break; - case TgMenu.SetTgMessageStartId: - tgClient.TgSettings.SetMessageStartId(); - break; - case TgMenu.SetTgMessageCount: - tgClient.TgSettings.SetMessageCount(); - break; - } + menu.ShowTable(locale.TgSettings); + menuSettings = menu.SetOptionsSetupTg(); + switch (menuSettings) + { + case TgMenuSettings.SourceUsername: + tgClient.TgSettings.SetSourceUserName(); + tgClient.PrepareCollectMessages(); + break; + case TgMenuSettings.DestDirectory: + tgClient.TgSettings.SetDestDirectory(); + break; + case TgMenuSettings.MessageCurrentId: + tgClient.TgSettings.SetMessageCurrentId(); + break; + } + } while (menuSettings is not TgMenuSettings.Return); } -void RunMenuJob(Action action) +void RunMenuJob(Action action) { - menu.ShowTable(locale.Info.MenuDownloadFiles); - log.MarkupLineStamp(locale.Info.StatusStart); + menu.ShowTable(locale.MenuDownloadFiles); + log.MarkupLineStamp(locale.StatusStart); + if (!menu.CheckTgSettings()) + { + log.MarkupLineStampWarning(locale.TgMustSetSettings); + Console.ReadKey(); + return; + } AnsiConsole.Status() .AutoRefresh(true) - .Spinner(Spinner.Known.Aesthetic) + .Spinner(Spinner.Known.Ascii) .SpinnerStyle(Style.Parse("green")) .Start("Thinking...", statusContext => { + globalStatusContext = statusContext; Stopwatch sw = new(); sw.Start(); - statusContext.Status($"{menu.GetStatusInfo(sw)} | Process job."); + statusContext.Status($"{menu.GetStatus(sw, + tgClient.TgSettings.MessageCurrentId, tgClient.TgSettings.MessageCount)} | Process job"); statusContext.Refresh(); - action(); + action(sw); sw.Stop(); - statusContext.Status($"{menu.GetStatusInfo(sw)} | Job is complete."); + statusContext.Status($"{menu.GetStatus(sw, + tgClient.TgSettings.MessageCurrentId, tgClient.TgSettings.MessageCount)} | Job is complete"); statusContext.Refresh(); }); - log.MarkupLineStamp(locale.Info.MenuReturn); + globalStatusContext = null; + log.MarkupLineStamp(locale.MenuReturn); Console.ReadKey(); } void ConnectTgClient() { + menu.ShowTable(locale.TgClientConnect); tgClient.Connect(); tgClient.CollectAllChats().GetAwaiter().GetResult(); - tgClient.PrintChatsInfo(tgClient.ListSmallGroups, "small groups", true); - tgClient.PrintChannelsInfo(tgClient.ListGroups, "groups", true); - tgClient.PrintChannelsInfo(tgClient.ListChannels, "channels", true); - log.MarkupLineStamp(locale.Info.AnyKey); + log.MarkupLineStampInfo(locale.TgClientSetupComplete); + Console.ReadKey(); +} + +void GetTgInfo() +{ + menu.ShowTable(locale.TgClientGetInfo); + if (!tgClient.IsConnected) + { + log.MarkupLineStampWarning(locale.TgMustClientConnect); + Console.ReadKey(); + return; + } + + Dictionary dicDialogs = tgClient.CollectAllDialogs(); + tgClient.PrintChatsInfo(dicDialogs, "dialogs", RefreshStatus); + + log.MarkupLineStampInfo(locale.TgGetInfoComplete); Console.ReadKey(); } -void DownloadFiles() +void DownloadFiles(Stopwatch sw) { - if (!menu.CheckTgSettings()) return; + AnsiConsole.Clear(); Channel channel = tgClient.PrepareCollectMessages(); - menu.ShowTable(locale.Info.MenuDownloadFiles); - tgClient.CollectMessages(channel).GetAwaiter().GetResult(); + menu.ShowTable(locale.MenuDownloadFiles); + tgClient.CollectMessages(channel, sw, RefreshStatus); + tgClient.TgSettings.SetMessageCurrentIdDefault(); } + +void RefreshStatus(string message) +{ + //AnsiConsole.Clear(); + if (globalStatusContext is null) return; + globalStatusContext.Status(log.GetMarkupString($"{menu.GetStatus(tgClient.TgSettings.MessageCount, tgClient.TgSettings.MessageCurrentId)} | {message}")); + globalStatusContext.Refresh(); +} \ No newline at end of file diff --git a/TgDownloaderConsole/TgDownloaderConsole.csproj b/TgDownloaderConsole/TgDownloaderConsole.csproj index 329ffc0b..fe2298e4 100644 --- a/TgDownloaderConsole/TgDownloaderConsole.csproj +++ b/TgDownloaderConsole/TgDownloaderConsole.csproj @@ -5,7 +5,7 @@ enable disable 11.0 - 0.1.150.0 + 0.1.180.0 diff --git a/TgDownloaderConsoleTest/TgDownloaderConsoleTest.csproj b/TgDownloaderConsoleTest/TgDownloaderConsoleTest.csproj index 2e7869b0..cbbcb251 100644 --- a/TgDownloaderConsoleTest/TgDownloaderConsoleTest.csproj +++ b/TgDownloaderConsoleTest/TgDownloaderConsoleTest.csproj @@ -4,7 +4,7 @@ enable disable false - 0.1.150.0 + 0.1.180.0 diff --git a/TgDownloaderCore/Enums/TgMenu.cs b/TgDownloaderCore/Enums/TgMenu.cs index 4787d8cc..4576dfd4 100644 --- a/TgDownloaderCore/Enums/TgMenu.cs +++ b/TgDownloaderCore/Enums/TgMenu.cs @@ -6,10 +6,8 @@ namespace TgDownloaderCore.Enums; public enum TgMenu { Exit, - Return, - DownloadFiles, - SetTgSourceUsername, - SetTgDestDirectory, - SetTgMessageStartId, - SetTgMessageCount, + Connect, + Info, + Settings, + DownloadFiles } \ No newline at end of file diff --git a/TgDownloaderCore/Enums/TgMenuSettings.cs b/TgDownloaderCore/Enums/TgMenuSettings.cs new file mode 100644 index 00000000..645419f0 --- /dev/null +++ b/TgDownloaderCore/Enums/TgMenuSettings.cs @@ -0,0 +1,12 @@ +// This is an independent project of an individual developer. Dear PVS-Studio, please check it. +// PVS-Studio Static Code Analyzer for C, C++, C#, and Java: http://www.viva64.com + +namespace TgDownloaderCore.Enums; + +public enum TgMenuSettings +{ + Return, + SourceUsername, + DestDirectory, + MessageCurrentId, +} \ No newline at end of file diff --git a/TgDownloaderCore/Locales/LocaleInfoHelper.cs b/TgDownloaderCore/Helpers/LocaleHelper.cs similarity index 55% rename from TgDownloaderCore/Locales/LocaleInfoHelper.cs rename to TgDownloaderCore/Helpers/LocaleHelper.cs index 3ea6b7c2..9a72b7cc 100644 --- a/TgDownloaderCore/Locales/LocaleInfoHelper.cs +++ b/TgDownloaderCore/Helpers/LocaleHelper.cs @@ -1,43 +1,55 @@ // This is an independent project of an individual developer. Dear PVS-Studio, please check it. // PVS-Studio Static Code Analyzer for C, C++, C#, and Java: http://www.viva64.com -namespace TgDownloaderCore.Locales; +namespace TgDownloaderCore.Helpers; -public class LocaleInfoHelper +public class LocaleHelper { #region Design pattern "Lazy Singleton" - private static LocaleInfoHelper _instance; - public static LocaleInfoHelper Instance => LazyInitializer.EnsureInitialized(ref _instance); + private static LocaleHelper _instance; + public static LocaleHelper Instance => LazyInitializer.EnsureInitialized(ref _instance); #endregion - #region Public and private fields and properties + #region Public and private methods - public string AnyKey => "Type any key"; + public string InfoMessage(string message) => $"[green]i {message}[/]"; + public string WarningMessage(string message) => $"[red]x {message}[/]"; + + public string AppMainMenu => "Main menu"; public string AppName => "Name"; public string AppTitle => "TG-Downloader"; public string AppValue => "Value"; public string AppVersion => "App version"; public string DestDirectory => "Enter destination directory:"; + public string DirIsNotExists => "Directory is not exists!"; + public string DirNotFound(string dir) => $"Directory '{dir}' is not found!"; public string MenuDownloadFiles => "Download files"; public string MenuReturn => "Type any key to return into the main menu."; - public string MenuSetupTg => "Setup TG"; public string MenuSwitchNumber => "Switch menu number: "; public string MoveUpDown => "(Move up and down to switch select)"; public string StatusException => "Exception: "; public string StatusFinish(Stopwatch sw) => $"Job is finished. Elapsed time: {sw.Elapsed}."; public string StatusInnerException => "Inner exception: "; public string StatusStart => "Job is started"; + public string TgClientConnect => "Connect the TG client"; + public string TgClientGetInfo => "Info about me"; + public string TgClientSetupComplete => "Setup the TG client was complete"; public string TgClientUserId => "My user ID"; public string TgClientUserIsActive => "My user active"; public string TgClientUserName => "My user name"; public string TgClientUserStatus => "My user status"; + public string TgGetDialogsInfo => "Getting all dialogs info"; + public string TgGetInfoComplete => "Get TG info was complete"; + public string TgMustClientConnect => "You must connect the client before"; + public string TgMustSetSettings => "You must setup the settings before"; + public string TgSettings => "Settings"; public string TgSettingsDestDirectory => "Dest directory"; - public string TgSettingsSourceUserName => "Source user name"; - public string TgSettingsMessageStartId => "Message start ID"; public string TgSettingsMessageCount => "Messages count"; - public string TgSettingsMessageMaxCount => "Messages max count"; + public string TgSettingsMessageStartId => "Message current ID"; + public string TgSettingsNotSet => ""; + public string TgSettingsSourceUserName => "Source user name"; public string TgSetupApiHash => "Type API hash: "; public string TgSetupAppId => "Type APP ID: "; public string TgSetupCode => "Type code: "; @@ -46,7 +58,9 @@ public class LocaleInfoHelper public string TgSetupNotifications => "Type use notifications: "; public string TgSetupPassword => "Type password: "; public string TgSetupPhone => "Type phone number: "; - public string[] MenuMain => new[] { "Exit", "Connect", "Settings", "Download files" }; + public string TypeTgMessageStartId => "Type the message start ID (example: 1): "; + public string TypeTgSourceUserName => "Type the source user name (example: https://t.me/some_channel): "; + public string[] MenuMain => new[] { "Exit", "Connect", "Info", "Settings", "Download files" }; #endregion } \ No newline at end of file diff --git a/TgDownloaderCore/Helpers/LogHelper.cs b/TgDownloaderCore/Helpers/LogHelper.cs index a7bc773e..e93f3d5c 100644 --- a/TgDownloaderCore/Helpers/LogHelper.cs +++ b/TgDownloaderCore/Helpers/LogHelper.cs @@ -62,17 +62,35 @@ public void SetAskBool(AskBoolDelegate askBool) _askBool = askBool; } - public string GetMarkupString(string line) => - line.Replace("[", "[[").Replace("]", "]]"); + public string GetMarkupString(string message) => + message + .Replace("[", "[[").Replace("]", "]]") + .Replace("'", "''") + ; - public void MarkupLineStamp(string message) + public string GetLineStamp(string message) => + $" {DateTime.Now:yyyy-MM-dd HH:mm:ss} | {GetMarkupString(message)}"; + + public void MarkupLineStamp(string message) => _markupLineStamp(GetLineStamp(message)); + + public string GetLineStampInfo(string message) { message = message.Replace("[", "[[").Replace("]", "]]"); message = message.Replace("'", "''"); - string result = $"{DateTime.Now:yyyy-MM-dd HH:mm:ss} | {message}"; - _markupLineStamp(result); + return $"[green] {DateTime.Now:yyyy-MM-dd HH:mm:ss} | i {message}[/]"; } + public void MarkupLineStampInfo(string message) => _markupLineStamp(GetLineStampInfo(message)); + + public string GetLineStampWarning(string message) + { + message = message.Replace("[", "[[").Replace("]", "]]"); + message = message.Replace("'", "''"); + return $"[red] {DateTime.Now:yyyy-MM-dd HH:mm:ss} | x {message}[/]"; + } + + public void MarkupLineStampWarning(string message) => _markupLineStamp(GetLineStampWarning(message)); + public string AskString(string message) => _askString(message); public int AskInt(string message) => _askInt(message); diff --git a/TgDownloaderCore/Helpers/TgClientHelper.cs b/TgDownloaderCore/Helpers/TgClientHelper.cs index ccd11eba..790fb1f1 100644 --- a/TgDownloaderCore/Helpers/TgClientHelper.cs +++ b/TgDownloaderCore/Helpers/TgClientHelper.cs @@ -1,12 +1,14 @@ // This is an independent project of an individual developer. Dear PVS-Studio, please check it. // PVS-Studio Static Code Analyzer for C, C++, C#, and Java: http://www.viva64.com -using TgDownloaderCore.Locales; using TgDownloaderCore.Models; +using TgDownloaderCore.Utils; +using Channel = TL.Channel; +using Document = TL.Document; namespace TgDownloaderCore.Helpers; -public class TgClientHelper +public partial class TgClientHelper { #region Design pattern "Lazy Singleton" @@ -31,39 +33,29 @@ public User MySelfUser { if (_mySelfUser is not null) return _mySelfUser; - _mySelfUser = IsConnected? WClient.LoginUserIfNeeded().ConfigureAwait(true).GetAwaiter().GetResult() : new(); + _mySelfUser = IsConnected ? WClient.LoginUserIfNeeded().ConfigureAwait(true).GetAwaiter().GetResult() : new(); return _mySelfUser; } } - private Dictionary _dicChatsAll; - public Dictionary DicChatsAll - { - get => _dicChatsAll; - private set - { - _dicChatsAll = value; - DtDicChatsAll = DateTime.Now; - } - } - public DateTime DtDicChatsAll { get; private set; } + public Dictionary DicChatsAll { get; private set; } public Dictionary DicChatsUpdated { get; } - public Dictionary DicDialogsAll { get; } public Dictionary DicUsersUpdated { get; } public List ListChannels { get; } public List ListGroups { get; } + public List ListChats { get; } public List ListSmallGroups { get; } public List> HashesChannels { get; private set; } public List> HashesUsers { get; private set; } - + public TgClientHelper() { DicChatsAll = new(); DicChatsUpdated = new(); - DicDialogsAll = new(); DicUsersUpdated = new(); HashesChannels = new(); HashesUsers = new(); + ListChats = new(); ListChannels = new(); ListGroups = new(); ListSmallGroups = new(); @@ -82,15 +74,15 @@ public string GetConfig(string what) { return what switch { - "api_id" => Log.AskString(Locale.Info.TgSetupAppId), - "api_hash" => Log.AskString(Locale.Info.TgSetupApiHash), - "phone_number" => Log.AskString(Locale.Info.TgSetupPhone), - "verification_code" => Log.AskString(Locale.Info.TgSetupCode), - "notifications" => Log.AskBool(Locale.Info.TgSetupNotifications).ToString(), - "first_name" => Log.AskString(Locale.Info.TgSetupFirstName), - "last_name" => Log.AskString(Locale.Info.TgSetupLastName), + "api_id" => Log.AskString(Log.GetLineStampInfo(Locale.TgSetupAppId)), + "api_hash" => Log.AskString(Log.GetLineStampInfo(Locale.TgSetupApiHash)), + "phone_number" => Log.AskString(Log.GetLineStampInfo(Locale.TgSetupPhone)), + "verification_code" => Log.AskString(Log.GetLineStampInfo(Locale.TgSetupCode)), + "notifications" => Log.AskBool(Log.GetLineStampInfo(Locale.TgSetupNotifications)).ToString(), + "first_name" => Log.AskString(Log.GetLineStampInfo(Locale.TgSetupFirstName)), + "last_name" => Log.AskString(Log.GetLineStampInfo(Locale.TgSetupLastName)), "session_pathname" => "TgDownloader.session", - "password" => Log.AskString(Locale.Info.TgSetupPassword), + "password" => Log.AskString(Log.GetLineStampInfo(Locale.TgSetupPassword)), _ => null }; // if enabled 2FA @@ -112,27 +104,26 @@ public void Connect() WClient = new(GetConfig); WClient.OnUpdate += Client_OnUpdate; - Log.MarkupLineStamp("Setup the TG Client was complete"); _ = MySelfUser; } - public long ReduceChatId(long chatId) => + public long ReduceChatId(long chatId) => !$"{chatId}".StartsWith("-100") ? chatId : Convert.ToInt64($"{chatId}"[4..]); - public long FixChatId(long chatId) => + public long FixChatId(long chatId) => $"{chatId}".StartsWith("-100") ? chatId : Convert.ToInt64($"-100{chatId}"); public User GetUserUpdated(long id) => DicUsersUpdated.TryGetValue(ReduceChatId(id), out User user) ? user : new(); - + public string GetUserUpdatedName(long id) => DicUsersUpdated.TryGetValue(ReduceChatId(id), out User user) ? user.username : string.Empty; - + public ChatBase GetChat(long id) => DicChatsAll.TryGetValue(ReduceChatId(id), out ChatBase chat) ? chat : new Chat(); - + public ChatBase GetChatUpdated(long id) => DicChatsUpdated.TryGetValue(ReduceChatId(id), out ChatBase chat) ? chat : new Chat(); - + public Channel GetChannel(long id) => DicChatsAll.TryGetValue(ReduceChatId(id), out ChatBase chat) ? chat as Channel ?? new() : new(); - + public Channel GetChannel(string userName) { foreach (KeyValuePair chatBase in DicChatsAll) @@ -145,9 +136,9 @@ public Channel GetChannel(string userName) } return new(); } - + public Channel GetChannelUpdated(long id) => DicChatsUpdated.TryGetValue(ReduceChatId(id), out ChatBase chat) ? chat as Channel ?? new() : new(); - + public string GetChatName(long id) => DicChatsAll.TryGetValue(ReduceChatId(id), out ChatBase chat) ? chat.ToString() : string.Empty; public string GetChatUpdatedName(long id) => DicChatsUpdated.TryGetValue(ReduceChatId(id), out ChatBase chat) ? chat.ToString() : string.Empty; @@ -166,35 +157,27 @@ public async Task CollectAllChats() FillListChats(DicChatsAll); } - private void FillListChats(Dictionary dic) + public Dictionary CollectAllDialogs() { - ListSmallGroups.Clear(); - ListGroups.Clear(); - ListChannels.Clear(); - - foreach (KeyValuePair item in dic) + if (IsConnected) { - switch (item.Value) - { - case Chat smallGroup when (smallGroup.flags & Chat.Flags.deactivated) is 0: - ListSmallGroups.Add(item.Value); - break; - case Channel { IsGroup: true } group: - //case Channel group: // no broadcast flag => it's a big group, also called superGroup or megaGroup - ListGroups.Add(group); - break; - case Channel channel: - //case Channel channel when (channel.flags & Channel.Flags.broadcast) is not 0: - ListChannels.Add(channel); - break; - } + Messages_Dialogs messages = WClient.Messages_GetAllDialogs() + .ConfigureAwait(true).GetAwaiter().GetResult(); + return messages.chats; } + return new(); } - private void FillListDialogs(Dictionary dic) + private void FillListChats(Dictionary dic) { + ListChannels.Clear(); + ListChats.Clear(); + ListGroups.Clear(); + ListSmallGroups.Clear(); + foreach (KeyValuePair item in dic) { + ListChats.Add(item.Value); switch (item.Value) { case Chat smallGroup when (smallGroup.flags & Chat.Flags.deactivated) is 0: @@ -217,10 +200,9 @@ private async Task Client_OnUpdate(IObject arg) if (arg is not UpdatesBase updates) return; await Task.Delay(TimeSpan.FromMilliseconds(1)).ConfigureAwait(false); - try + TryCatchAction(() => { updates.CollectUsersChats(DicUsersUpdated, DicChatsUpdated); - foreach (Update update in updates.UpdateList) { switch (update) @@ -275,22 +257,16 @@ private async Task Client_OnUpdate(IObject arg) // break; default: //ConsoleUtils.MarkupLine(update.GetType().Name); - await Client_DisplayMessage(null); + Client_DisplayMessage(null); break; // there are much more update types than the above example cases } } - } - catch (Exception ex) - { - Log.MarkupLineStamp(ex.Message); - if (ex.InnerException is not null) - Log.MarkupLineStamp(ex.InnerException.Message); - } + }); } - private Task Client_DisplayMessage(MessageBase messageBase, bool edit = false) + private void Client_DisplayMessage(MessageBase messageBase, bool edit = false) { - if (messageBase is null) return Task.CompletedTask; + if (messageBase is null) return; if (edit) Console.Write("(Edit): "); switch (messageBase) { @@ -301,7 +277,6 @@ private Task Client_DisplayMessage(MessageBase messageBase, bool edit = false) Log.MarkupLineStamp($"{GetPeerUpdatedName(messageService.from_id)} in {GetPeerUpdatedName(messageService.peer_id)} [{messageService.action.GetType().Name[13..]}]"); break; } - return Task.CompletedTask; } public async Task PrintSendAsync(Messages_Chats messagesChats) @@ -348,188 +323,159 @@ public List SortListChannels(List channels) return result; } - public void PrintChatsInfo(List chats, string name, bool isSort) + public void PrintChatsInfo(Dictionary dicChats, string name, Action refreshStatus) { - if (isSort) - chats = SortListChats(chats); - Log.MarkupLineStamp($"Found {name}: {chats.Count}"); + Log.MarkupLineStampInfo($"Found {name}: {dicChats.Count}"); + Log.MarkupLineStampInfo(Locale.TgGetDialogsInfo); + foreach (KeyValuePair dicChat in dicChats) + { + TryCatchAction(() => + { + switch (dicChat.Value) + { + case Channel channel: + PrintChatsInfoChannel(channel, false); + break; + default: + Log.MarkupLineStamp(GetChatInfo(dicChat.Value)); + break; + } + }, refreshStatus); + } } - public void PrintChannelsInfo(List channels, string name, bool isSort) + private void PrintChatsInfoChannel(Channel channel, bool isFull) { - if (isSort) - channels = SortListChannels(channels); - Log.MarkupLineStamp($"Found {name}: {channels.Count}"); + Messages_ChatFull fullChannel = WClient.Channels_GetFullChannel(channel).ConfigureAwait(true).GetAwaiter().GetResult(); + if (fullChannel.full_chat is ChannelFull channelFull) + Log.MarkupLineStamp(GetChannelFullInfo(channelFull, channel, isFull)); + else + Log.MarkupLineStamp(GetChatFullBaseInfo(fullChannel.full_chat, channel, isFull)); } - public void PrintChatFullBaseInfo(ChatFullBase chatFull) + public string GetChatInfo(ChatBase chat) { - if (chatFull is null) return; - - if (chatFull.BotInfo is not null) - foreach (BotInfo botInfo in chatFull.BotInfo) - { - //ConsoleUtils.MarkupLine(botInfo.commands); - //ConsoleUtils.MarkupLine(botInfo.description); - //ConsoleUtils.MarkupLine(botInfo.menu_button); - } - - if (chatFull.RecentRequesters is not null) - foreach (long requester in chatFull.RecentRequesters) - { - Log.MarkupLineStamp($"{nameof(requester)}: {requester}"); - } + if (chat is null) return string.Empty; + return + $"{nameof(chat.ID)}: {chat.ID} | " + + $"{nameof(chat.IsActive)}: {chat.IsActive} | " + + $"{nameof(chat.IsBanned)}: {chat.IsBanned()} | " + + $"{nameof(chat.Title)}: {chat.Title} | " + + $"{nameof(chat.GetType)}: {chat.GetType()}"; + } - Log.MarkupLineStamp($"{nameof(chatFull.RequestsPending)}: {chatFull.RequestsPending}"); + public string GetChannelFullInfo(ChannelFull channelFull, ChatBase chat, bool isFull) + { + if (channelFull is null) return string.Empty; + string result = GetChatInfo(chat); + if (isFull) + result += " | " + + $"{nameof(channelFull.About)}: {channelFull.About} | " + + $"{nameof(channelFull.TtlPeriod)}: {channelFull.TtlPeriod} | " + + $"{nameof(channelFull.read_inbox_max_id)}: {channelFull.read_inbox_max_id}"; + return result; + } - Log.MarkupLineStamp( + public string GetChatFullBaseInfo(ChatFullBase chatFull, ChatBase chat, bool isFull) + { + if (chatFull is null) return string.Empty; + string result = GetChatInfo(chat); + if (isFull) + result += " | " + $"{nameof(chatFull.About)}: {chatFull.About} | " + - $"{nameof(chatFull.ID)}: {chatFull.ID} | " + - $"{nameof(chatFull.GetType)}: {chatFull.GetType()} | " + - $"{nameof(chatFull.TtlPeriod)}: {chatFull.TtlPeriod} | "); + $"{nameof(chatFull.TtlPeriod)}: {chatFull.TtlPeriod}"; + return result; } - public void PrintChannelFullInfo(ChannelFull channelFull) + public int GetChannelMessagesCount(Channel channel) { - if (channelFull is null) return; - - if (channelFull.BotInfo is not null) - foreach (BotInfo botInfo in channelFull.BotInfo) - { - //ConsoleUtils.MarkupLine(botInfo.commands); - //ConsoleUtils.MarkupLine(botInfo.description); - //ConsoleUtils.MarkupLine(botInfo.menu_button); - } - - if (channelFull.RecentRequesters is not null) - foreach (long requester in channelFull.RecentRequesters) - { - Log.MarkupLineStamp($"{nameof(requester)}: {requester}"); - } - - Log.MarkupLineStamp($"{nameof(channelFull.RequestsPending)}: {channelFull.RequestsPending}"); - Log.MarkupLineStamp($"{nameof(channelFull.read_inbox_max_id)}: {channelFull.read_inbox_max_id}"); - - Log.MarkupLineStamp( - $"{nameof(channelFull.About)}: {channelFull.About} | " + - $"{nameof(channelFull.ID)}: {channelFull.ID} | " + - $"{nameof(channelFull.GetType)}: {channelFull.GetType()} | " + - $"{nameof(channelFull.TtlPeriod)}: {channelFull.TtlPeriod} | "); + Messages_ChatFull fullChannel = WClient.Channels_GetFullChannel(channel).ConfigureAwait(true).GetAwaiter().GetResult(); + return fullChannel.full_chat is ChannelFull channelFull ? channelFull.read_inbox_max_id : 0; } - public int GetChannelMessagesCount(ChatFullBase chatFullBase) => - chatFullBase is not ChannelFull channelFull ? 0 : channelFull.read_inbox_max_id; - public Channel PrepareCollectMessages() { Channel channel = GetChannel(TgSettings.SourceUserName); if (channel.id is 0) return channel; - Messages_ChatFull fullChannel = WClient.Channels_GetFullChannel(channel).ConfigureAwait(true).GetAwaiter().GetResult(); - if (fullChannel.full_chat is ChannelFull channelFull) - PrintChannelFullInfo(channelFull); - else - PrintChatFullBaseInfo(fullChannel.full_chat); - TgSettings.SetMessageMaxCount(GetChannelMessagesCount(fullChannel.full_chat)); - + PrintChatsInfoChannel(channel, true); + TgSettings.SetMessageCount(GetChannelMessagesCount(channel)); + return channel; } - public async Task CollectMessages(Channel channel) + public void CollectMessages(Channel channel, Stopwatch sw, Action refreshStatus) { if (channel.id is 0) return; - try + TryCatchAction(() => { - int lastId = TgSettings.MessageCount < 1 ? TgSettings.MessageStartId + 1 : TgSettings.MessageStartId + TgSettings.MessageCount; - - while (TgSettings.MessageStartId < lastId && TgSettings.MessageStartId <= TgSettings.MessageMaxCount) + _ = MySelfUser; + while (TgSettings.MessageCurrentId <= TgSettings.MessageCount) { - _ = MySelfUser; Messages_MessagesBase messages = - await WClient.Channels_GetMessages(channel, TgSettings.MessageStartId).ConfigureAwait(true); + WClient.Channels_GetMessages(channel, TgSettings.MessageCurrentId).ConfigureAwait(true).GetAwaiter().GetResult(); foreach (MessageBase message in messages.Messages) { - // It could be: "(no message)". - Log.MarkupLineStamp($"Read the message {message.ID} | {message}"); - //string fromId = message.From is not null ? message.From.ID.ToString() : string.Empty; - //string replyToId = message.ReplyTo is not null ? message.ReplyTo.reply_to_msg_id.ToString() : string.Empty; - await DownloadFile(message, TgSettings.DestDirectory); + // It could be: "(no message)" + DownloadFile(message, TgSettings.DestDirectory, refreshStatus); } - TgSettings.AddMessageStartId(); - if (TgSettings.MessageCount < 1) - lastId = TgSettings.MessageStartId + 1; + TgSettings.AddMessageCurrentId(); } - } - catch (Exception ex) - { - Log.MarkupLineStamp(ex.Message); - if (ex.InnerException is not null) - Log.MarkupLineStamp(ex.InnerException.Message); - } + }, refreshStatus); } - private async Task DownloadFile(MessageBase messageBase, string folder) + private void DownloadFile(MessageBase messageBase, string folder, Action refreshStatus) { - try + TryCatchAction(() => { if (messageBase is null) return; - if (messageBase is not Message { media: MessageMediaDocument { document: Document document } }) return; - + if (messageBase is not Message { media: MessageMediaDocument { document: Document document } }) + { + refreshStatus($"Read the message {messageBase.ID} without document"); + return; + } string fileName = Path.Combine(folder, document.Filename); - if (!CheckDownloadFileProcess(fileName, document)) return; - DeleteFileIfExists(fileName); - - // DownloadFile v1. - //await File.WriteAllTextAsync(path, content); - - // DownloadFile v2. - //await using MemoryStream memoryStream = new(); - //await WClient.DownloadFileAsync(document, memoryStream); - //byte[] bytes = memoryStream.ToArray(); - //await using FileStream fileStream = File.Create(fileName); - //await fileStream.WriteAsync(bytes); - //fileStream.Close(); - //memoryStream.Close(); - - // DownloadFile v3. - await using FileStream fileStream = File.Create(fileName); - await WClient.DownloadFileAsync(document, fileStream); + (bool IsNeed, long Size) fileToDelete = IsFileNeedDelete(fileName, document, refreshStatus); + if (fileToDelete.IsNeed) + DeleteFile(fileName, fileToDelete.Size, refreshStatus); + refreshStatus($"Read the message {messageBase.ID} with document \"{document.Filename}\" (size {FileUtils.GetFileSizeString(document.size)}) in progress"); + // Download file. + using FileStream fileStream = File.Create(fileName); + WClient.DownloadFileAsync(document, fileStream).ConfigureAwait(true).GetAwaiter().GetResult(); fileStream.Close(); - } - catch (Exception ex) - { - string messageId = messageBase is not null ? messageBase.ID.ToString() : string.Empty; - Log.MarkupLineStamp($"Exception at the message ID: {messageId}"); - Log.MarkupLineStamp(ex.Message); - if (ex.InnerException is not null) - Log.MarkupLineStamp(ex.InnerException.Message); - } + // Callback. + refreshStatus($"Read the message {messageBase.ID} with document \"{fileName}\" was complete"); + }, refreshStatus); } - private bool CheckDownloadFileProcess(string fileName, Document document) + private (bool, long) IsFileNeedDelete(string fileName, Document document, Action refreshStatus) { - bool result = true; - if (File.Exists(fileName)) + bool result = false; + long size = 0; + TryCatchAction(() => { - Log.MarkupLineStamp($"File {Path.GetFileName(fileName)} is exists"); - result = false; - using FileStream fileStream = File.OpenRead(fileName); - if (fileStream.Length < document.size) + if (File.Exists(fileName)) { - Log.MarkupLineStamp($"File {Path.GetFileName(fileName)} have {fileStream.Length} size, but document have {document.size} size. It will be re-download"); - result = true; + using FileStream fileStream = File.OpenRead(fileName); + size = fileStream.Length; + result = fileStream.Length < document.size; + fileStream.Close(); } - fileStream.Close(); - } - return result; + }, refreshStatus); + return (result, size); } - private void DeleteFileIfExists(string fileName) + private void DeleteFile(string fileName, long size, Action refreshStatus) { if (!File.Exists(fileName)) return; - File.Delete(fileName); - Log.MarkupLineStamp($"File {Path.GetFileName(fileName)} was deleted"); + TryCatchAction(() => + { + refreshStatus($"Delete file \"{fileName}\" (size {FileUtils.GetFileSizeString(size)}) in progress"); + File.Delete(fileName); + //Log.MarkupLineStampInfo($"Delete file \"{fileName}\" (size {FileUtils.GetFileSizeString(size)})"); + refreshStatus($"Delete file \"{fileName}\" (size {FileUtils.GetFileSizeString(size)}) was complete"); + }, refreshStatus); } private void PrintAccessHashInfo(Channel channel, string userName) @@ -573,7 +519,7 @@ private void PrintAccessHashInfo(Channel channel, string userName) Log.MarkupLineStamp("Saving all collected access hashes to disk for next run..."); HashesChannels = WClient.AllAccessHashesFor().ToList(); HashesUsers = WClient.AllAccessHashesFor().ToList(); - + //string StateFilename = "SavedState.json"; //using FileStream stateStream = File.Create(StateFilename); //JsonSerializer.Serialize(stateStream, this); diff --git a/TgDownloaderCore/Helpers/TgClientHelperActions.cs b/TgDownloaderCore/Helpers/TgClientHelperActions.cs new file mode 100644 index 00000000..7076f287 --- /dev/null +++ b/TgDownloaderCore/Helpers/TgClientHelperActions.cs @@ -0,0 +1,45 @@ +// This is an independent project of an individual developer. Dear PVS-Studio, please check it. +// PVS-Studio Static Code Analyzer for C, C++, C#, and Java: http://www.viva64.com + +using System.Runtime.CompilerServices; + +namespace TgDownloaderCore.Helpers; + +public partial class TgClientHelper +{ + private void TryCatchAction(Action action, Action refreshStatus = null, + [CallerFilePath] string filePath = "", [CallerLineNumber] int lineNumber = 0, [CallerMemberName] string memberName = "") + { + try + { + action(); + } + catch (Exception ex) + { + string fileName = Path.GetFileName(filePath); + if (refreshStatus is not null) + { + //Log.MarkupLineStamp($"Exception at | {nameof(fileName)}: {fileName} | {nameof(lineNumber)}: {lineNumber} | {nameof(memberName)}: {memberName}"); + refreshStatus($"Exception at | {nameof(fileName)}: {fileName} | {nameof(lineNumber)}: {lineNumber} | {nameof(memberName)}: {memberName}"); + //Log.MarkupLineStamp(ex.Message); + refreshStatus(ex.Message); + if (ex.InnerException is not null) + { + //Log.MarkupLineStamp(ex.InnerException.Message); + refreshStatus(ex.InnerException.Message); + } + /* + string messageId = messageBase is not null ? messageBase.ID.ToString() : string.Empty; + Log.MarkupLineStamp($"Exception | {messageId} | {ex.Message}"); + refreshStatus($"Exception | {messageId} |"); + refreshStatus(ex.Message); + if (ex.InnerException is not null) + { + Log.MarkupLineStamp(ex.InnerException.Message); + refreshStatus(ex.InnerException.Message); + } + */ + } + } + } +} \ No newline at end of file diff --git a/TgDownloaderCore/Locales/LocaleHelper.cs b/TgDownloaderCore/Locales/LocaleHelper.cs deleted file mode 100644 index ed4fea89..00000000 --- a/TgDownloaderCore/Locales/LocaleHelper.cs +++ /dev/null @@ -1,29 +0,0 @@ -// This is an independent project of an individual developer. Dear PVS-Studio, please check it. -// PVS-Studio Static Code Analyzer for C, C++, C#, and Java: http://www.viva64.com - -namespace TgDownloaderCore.Locales; - -public class LocaleHelper -{ - #region Design pattern "Lazy Singleton" - - private static LocaleHelper _instance; - public static LocaleHelper Instance => LazyInitializer.EnsureInitialized(ref _instance); - - #endregion - - #region Public and private fields and properties - - public LocaleInfoHelper Info => LocaleInfoHelper.Instance; - public LocaleQuestionHelper Question => LocaleQuestionHelper.Instance; - public LocaleWarningHelper Warning => LocaleWarningHelper.Instance; - - #endregion - - #region Public and private methods - - public string InfoMessage(string message) => $"[green]i {message}[/]"; - public string WarningMessage(string message) => $"[red]i {message}[/]"; - - #endregion -} \ No newline at end of file diff --git a/TgDownloaderCore/Locales/LocaleQuestionHelper.cs b/TgDownloaderCore/Locales/LocaleQuestionHelper.cs deleted file mode 100644 index ac7a6b37..00000000 --- a/TgDownloaderCore/Locales/LocaleQuestionHelper.cs +++ /dev/null @@ -1,22 +0,0 @@ -// This is an independent project of an individual developer. Dear PVS-Studio, please check it. -// PVS-Studio Static Code Analyzer for C, C++, C#, and Java: http://www.viva64.com - -namespace TgDownloaderCore.Locales; - -public class LocaleQuestionHelper -{ - #region Design pattern "Lazy Singleton" - - private static LocaleQuestionHelper _instance; - public static LocaleQuestionHelper Instance => LazyInitializer.EnsureInitialized(ref _instance); - - #endregion - - #region Public and private fields and properties - - public string TypeTgSourceUserName => "Type the source user name: "; - public string TypeTgMessageCount => "Type the messages count (default value: 0): "; - public string TypeTgMessageStartId => "Type the message start ID (default value: 1): "; - - #endregion -} \ No newline at end of file diff --git a/TgDownloaderCore/Locales/LocaleWarningHelper.cs b/TgDownloaderCore/Locales/LocaleWarningHelper.cs deleted file mode 100644 index b16c570b..00000000 --- a/TgDownloaderCore/Locales/LocaleWarningHelper.cs +++ /dev/null @@ -1,22 +0,0 @@ -// This is an independent project of an individual developer. Dear PVS-Studio, please check it. -// PVS-Studio Static Code Analyzer for C, C++, C#, and Java: http://www.viva64.com - -namespace TgDownloaderCore.Locales; - -public class LocaleWarningHelper -{ - #region Design pattern "Lazy Singleton" - - private static LocaleWarningHelper _instance; - public static LocaleWarningHelper Instance => LazyInitializer.EnsureInitialized(ref _instance); - - #endregion - - #region Public and private fields and properties - - public string DirIsNotExists => "Directory is not exists!"; - public string DirNotFound(string dir) => $"Directory '{dir}' is not found!"; - public string TgSettingsNotSet => ""; - - #endregion -} \ No newline at end of file diff --git a/TgDownloaderCore/Models/TgSettingsModel.cs b/TgDownloaderCore/Models/TgSettingsModel.cs index 700e1918..3a7b7a56 100644 --- a/TgDownloaderCore/Models/TgSettingsModel.cs +++ b/TgDownloaderCore/Models/TgSettingsModel.cs @@ -2,7 +2,6 @@ // PVS-Studio Static Code Analyzer for C, C++, C#, and Java: http://www.viva64.com using TgDownloaderCore.Helpers; -using TgDownloaderCore.Locales; namespace TgDownloaderCore.Models; @@ -14,30 +13,33 @@ public class TgSettingsModel public LogHelper Log => LogHelper.Instance; public string SourceUserName { get; private set; } public string DestDirectory { get; private set; } - public int MessageStartId { get; private set; } + public int MessageCurrentId { get; private set; } public int MessageCount { get; private set; } - public int MessageMaxCount { get; private set; } public TgSettingsModel() { - SourceUserName = string.Empty; - DestDirectory = string.Empty; - MessageStartId = -1; - MessageCount = -1; - MessageMaxCount = -1; + SetDefault(); } #endregion #region Public and private methods - public void SetSourceUserName() + private void SetDefault() { SourceUserName = string.Empty; + DestDirectory = string.Empty; + MessageCurrentId = 1; + MessageCount = 0; + } + + public void SetSourceUserName() + { + SetDefault(); bool isCheck; do { - string userName = Log.AskString(Locale.Question.TypeTgSourceUserName); + string userName = Log.AskString(Locale.TypeTgSourceUserName); if (!string.IsNullOrEmpty(userName)) { SourceUserName = userName.StartsWith(@"https://t.me/") @@ -57,13 +59,13 @@ public void SetDestDirectory() { if (!string.IsNullOrEmpty(DestDirectory) && !Directory.Exists(DestDirectory)) - Log.MarkupLineStamp(Locale.Warning.DirNotFound(DestDirectory)); - DestDirectory = Log.AskString(Locale.Info.DestDirectory); + Log.MarkupLineStamp(Locale.DirNotFound(DestDirectory)); + DestDirectory = Log.AskString(Locale.DestDirectory); } while (!Directory.Exists(DestDirectory)); if (!Directory.Exists(DestDirectory)) { DestDirectory = string.Empty; - Log.MarkupLineStamp(Locale.Warning.DirIsNotExists); + Log.MarkupLineStamp(Locale.DirIsNotExists); } else { @@ -72,27 +74,17 @@ public void SetDestDirectory() } while (!isCheck); } - public void SetMessageStartId() + public void SetMessageCurrentId() { - MessageStartId = Log.AskInt(Locale.Question.TypeTgMessageStartId); - MessageStartId = MessageStartId < 1 ? 1 : MessageStartId; + MessageCurrentId = Log.AskInt(Locale.TypeTgMessageStartId); + MessageCurrentId = MessageCurrentId < 1 ? 1 : MessageCurrentId; } - public void AddMessageStartId(int count = 1) - { - MessageStartId += count; - } + public void SetMessageCurrentIdDefault() => MessageCurrentId = 1; - public void SetMessageCount() - { - MessageCount = Log.AskInt(Locale.Question.TypeTgMessageCount); - MessageCount = MessageCount < 0 ? 0 : MessageCount; - } + public void AddMessageCurrentId(int count = 1) => MessageCurrentId += count; - public void SetMessageMaxCount(int count) - { - MessageMaxCount = count; - } + public void SetMessageCount(int count) => MessageCount = count; #endregion } \ No newline at end of file diff --git a/TgDownloaderCore/TgDownloaderCore.csproj b/TgDownloaderCore/TgDownloaderCore.csproj index 8e3b08fb..4883b4fd 100644 --- a/TgDownloaderCore/TgDownloaderCore.csproj +++ b/TgDownloaderCore/TgDownloaderCore.csproj @@ -3,12 +3,8 @@ net7.0 enable disable - 0.1.150.0 + 0.1.180.0 - - - - diff --git a/TgDownloaderCore/Utils/FileUtils.cs b/TgDownloaderCore/Utils/FileUtils.cs index 725ca4dd..03d8f01d 100644 --- a/TgDownloaderCore/Utils/FileUtils.cs +++ b/TgDownloaderCore/Utils/FileUtils.cs @@ -2,7 +2,6 @@ // PVS-Studio Static Code Analyzer for C, C++, C#, and Java: http://www.viva64.com using TgDownloaderCore.Helpers; -using TgDownloaderCore.Locales; namespace TgDownloaderCore.Utils; @@ -128,9 +127,9 @@ public static long CalculateDirSize(string dir) } catch (Exception ex) { - Log.MarkupLineStamp(Locale.Info.StatusException + Log.GetMarkupString(ex.Message)); + Log.MarkupLineStamp(Locale.StatusException + Log.GetMarkupString(ex.Message)); if (ex.InnerException is not null) - Log.MarkupLineStamp(Locale.Info.StatusInnerException + Log.GetMarkupString(ex.InnerException.Message)); + Log.MarkupLineStamp(Locale.StatusInnerException + Log.GetMarkupString(ex.InnerException.Message)); return 0L; } } @@ -141,5 +140,16 @@ public static long CalculateFileSize(string file) return new FileInfo(file).Length; } + public static string GetFileSizeString(long value) => + value > 0 + ? value switch + { + < 1024 => $"{value:###} B", + < 1024 * 1024 => $"{(double)value / 1024L:###} KB", + < 1024 * 1024 * 1024 => $"{(double)value / 1024L / 1024L:###} MB", + _ => $"{(double)value / 1024L / 1024L / 1024L:###} GB" + } + : "0 B"; + #endregion } \ No newline at end of file diff --git a/TgDownloaderCoreTest/TgDownloaderCoreTest.csproj b/TgDownloaderCoreTest/TgDownloaderCoreTest.csproj index 5d249221..6f1e0ba8 100644 --- a/TgDownloaderCoreTest/TgDownloaderCoreTest.csproj +++ b/TgDownloaderCoreTest/TgDownloaderCoreTest.csproj @@ -4,7 +4,7 @@ enable disable false - 0.1.150.0 + 0.1.180.0