private static void ShowExampleTables() { Table table = new Table("One", "Two", "Three"); table.AddRow("1", "2", "3"); table.AddRow("Short", "item", "Here"); table.AddRow("Longer items go here", "stuff stuff", "stuff"); table.Config = TableConfiguration.Default(); string test = String.Empty.PadRight(Console.WindowWidth, '-'); Console.Write(test); Console.SetCursorPosition(0, 0); Console.Write(table.ToString()); Console.WriteLine(); table.Config = TableConfiguration.Markdown(); Console.Write(table.ToString()); Console.WriteLine(); table.Config = TableConfiguration.MySql(); Console.Write(table.ToString()); Console.WriteLine(); table.Config = TableConfiguration.MySqlSimple(); Console.Write(table.ToString()); Console.WriteLine(); table.Config = TableConfiguration.Unicode(); Console.Write(table.ToString()); Console.WriteLine(); table.Config = TableConfiguration.UnicodeAlt(); Console.Write(table.ToString()); Console.WriteLine(); }
private static void ShowExampleTables() { ShowAlignedTables(); Console.WriteLine(); Table table = new Table("One", "Two", "Three"); table.AddRow("1", "2", "3"); table.AddRow("Short", "item", "Here"); table.AddRow("Longer items go here", "stuff stuff", "stuff"); table.Config = TableConfiguration.Default(); Console.Write(table.ToString()); Console.WriteLine(); table.Config = TableConfiguration.Markdown(); Console.Write(table.ToString()); Console.WriteLine(); table.Config = TableConfiguration.MySql(); Console.Write(table.ToString()); Console.WriteLine(); table.Config = TableConfiguration.MySqlSimple(); Console.Write(table.ToString()); Console.WriteLine(); table.Config = TableConfiguration.Unicode(); Console.Write(table.ToString()); Console.WriteLine(); table.Config = TableConfiguration.UnicodeAlt(); Console.Write(table.ToString()); Console.WriteLine(); }
/// <summary> /// Create table /// </summary> /// <param name="columns"></param> /// <param name="rows"></param> /// <param name="outputType"></param> /// <param name="hasInnerRows"></param> /// <returns></returns> private static string Create(IEnumerable <ColumnHeader> columns, IEnumerable <object[]> rows, TableOutputType outputType, bool hasInnerRows) { var table = new Table(columns.ToArray()); switch (outputType) { case TableOutputType.Text: table.Config = TableConfiguration.Default(); break; case TableOutputType.Unicode: table.Config = TableConfiguration.Unicode(); break; case TableOutputType.UnicodeAlt: table.Config = TableConfiguration.UnicodeAlt(); break; case TableOutputType.Markdown: table.Config = TableConfiguration.Markdown(); break; case TableOutputType.Html: table.Config = TableConfiguration.Unicode(); break; default: break; } table.Config.hasInnerRows = hasInnerRows; table.AddRows(rows); var ret = table.ToString(); if (outputType == TableOutputType.Html) { ret = ToHtml(ret); } return(ret); }
// column choice table private static void MultiColumnTable(string title, string[] descriptionLines, string[] options, int numberOfColumns) { // info column ColumnHeader titleHeader = new ColumnHeader(title, Alignment.Left, Alignment.Center); Table infoTable = new Table(titleHeader); infoTable.AddRow(" "); foreach (string descriptionLine in descriptionLines) { infoTable.AddRow(descriptionLine); } infoTable.Config = TableConfiguration.UnicodeAlt(); // options column table Table optionsTable = new Table(); // - header: empty lines space for (int i = 0; i < numberOfColumns; i++) { string emptyHeaderSpace = " "; optionsTable.AddColumn(emptyHeaderSpace); } // - columns: options // - add rows int maxRows = options.Length / numberOfColumns; for (int row = 1; row <= maxRows; row++) { int maxOptionsRow = numberOfColumns; var maxIndex = maxOptionsRow * row; var minIdex = maxIndex - maxOptionsRow; var optionsRow = new List <string>(); for (int index = minIdex; index < maxIndex; index++) { optionsRow.Add(options[index]); } optionsTable.AddRow(optionsRow.ToArray()); } optionsTable.AddRow("", "", "", ""); infoTable.Config = TableConfiguration.UnicodeAlt(); optionsTable.Config = TableConfiguration.Markdown(); DefaultTitile(); Console.Write(infoTable.ToString()); Console.Write(optionsTable.ToString()); }
/// <summary> /// Create table /// </summary> /// <param name="columns"></param> /// <param name="rows"></param> /// <param name="outputType"></param> /// <param name="hasInnerRows"></param> /// <returns></returns> private static string Create(IEnumerable <ColumnHeader> columns, IEnumerable <object[]> rows, TableOutputType outputType, bool hasInnerRows) { string ret; if (rows.Count() == 0) { ret = ""; } else if (outputType == TableOutputType.Html) { ret = ToHtml(columns, rows); } else if (outputType == TableOutputType.Json) { ret = ToJson(columns.ToArray(), rows, false); } else if (outputType == TableOutputType.JsonPretty) { ret = ToJson(columns.ToArray(), rows, true); } else { var table = new Table(columns.ToArray()); switch (outputType) { case TableOutputType.Text: table.Config = TableConfiguration.Default(); break; case TableOutputType.Unicode: table.Config = TableConfiguration.Unicode(); break; case TableOutputType.UnicodeAlt: table.Config = TableConfiguration.UnicodeAlt(); break; case TableOutputType.Markdown: table.Config = TableConfiguration.Markdown(); break; default: break; } table.Config.hasInnerRows = hasInnerRows; table.AddRows(rows); ret = table.ToString(); } return(ret); }
public static string Format(IEnumerable <object> lines, TableConfiguration configuration = null) { if (configuration == null) { configuration = TableConfiguration.Markdown(); } Table table = null; foreach (var line in lines) { var type = line.GetType(); if (table == null) { var headers = type.GetProperties() .SelectMany(Attribute.GetCustomAttributes) .OfType <FormatTableHeaderAttribute>() .Select(_ => new ColumnHeader(_.ColumnName, _.TextAlignment)) .ToArray(); table = new Table(headers) { Config = configuration }; } var values = type.GetProperties() .Where(prop => prop.CustomAttributes.Any(attr => attr.AttributeType == typeof(FormatTableHeaderAttribute))) .Select(prop => prop.GetValue(line)) .ToArray(); table.AddRow(values); } if (table == null) { return(string.Empty); } return(table.ToString()); }
public async override Task <int> OnExecuteAsync(CommandLineApplication app) { await base.OnExecuteAsync(app); var mediaitems = await _googlePhotosSvc.GetMediaItemsAsync(); if (mediaitems.IsNullOrEmpty()) { _console.WriteLine("Sorry, no media items available..."); return(0); } var table = new Table(string.Empty, "File Name", "Mime Type", "Id") { Config = TableConfiguration.Markdown() }; var i = 1; foreach (var mediaitem in mediaitems) { table.AddRow(i, mediaitem.filename, mediaitem.mimeType, mediaitem.id); i++; } return(0); }
public async override Task <int> OnExecuteAsync(CommandLineApplication app) { await base.OnExecuteAsync(app); var rootPath = Path.GetFullPath(path); _console.Write($"Checking for file(s)... "); var allFileInfos = GetFiles(path, searchPattern); var items = new List <MyMediaFileItem>(allFileInfos.Count); if (allFileInfos.IsNullOrEmpty()) { _console.WriteLine($" 0 files found at {rootPath}"); } else { var checkForUploadableFileTypes = allFileInfos.GroupBy(p => Path.GetExtension(p.Name), StringComparer.InvariantCultureIgnoreCase) .Select(g => new { Extension = g.Key, MimeType = MimeTypeMap.GetMimeType(g.Key), Count = g.Count(), TotalBytes = g.Sum(p => p.Length) }) .ToList(); _console.WriteLine($"located {allFileInfos.Count} file(s), breakdown of file types;"); _console.WriteLine(); //todo: do we also analyse the files with ImageSharp/Exif? var headers = new[] { new ColumnHeader("File Extension"), new ColumnHeader("Mime Type"), new ColumnHeader("Count", Alignment.Right), new ColumnHeader("Size (MB)", Alignment.Right), new ColumnHeader("Status") }; var table = new Table(headers) { Config = TableConfiguration.Markdown() }; foreach (var f in checkForUploadableFileTypes.OrderBy(p => p.Extension)) { var status = string.Empty; if (!GooglePhotosService.IsFileUploadableByExtension(f.Extension)) { status = "Unsupported file extension, will not be uploaded."; } table.AddRow(f.Extension, f.MimeType, f.Count, f.TotalBytes.GetSizeInMB().ToString("0.0"), status); } //below summary row breaks the progress bar somehow //table.AddRow(string.Empty, string.Empty, allFileInfos.Count, allFileInfos.Sum(p => p.Length.GetSizeInMB()).ToString("0.0"), string.Empty); Console.Write(table.ToString()); _console.WriteLine(); //add all uploadable files into a new collection foreach (var fileInfo in allFileInfos) { if (GooglePhotosService.IsFileUploadable(fileInfo.FullName)) { items.Add(new MyMediaFileItem { fileInfo = fileInfo }); } } } if (items.IsNullOrEmpty()) { _console.WriteLine($"{items.Count} uploadable file(s)"); return(0); } { //extract album information from the folder structure (if requested) _console.WriteLine($"{items.Count} file(s) to be uploaded;"); _console.WriteLine(); var headers = new[] { new ColumnHeader("Relative Path"), new ColumnHeader("Size (KB)", Alignment.Right), new ColumnHeader("Album(s)") }; var table = new Table(headers) { Config = TableConfiguration.Markdown() }; foreach (var item in items) { item.relPath = GetRelPath(rootPath, item.fileInfo); item.albums = GetAlbums(item); table.AddRow(item.relPath, item.fileInfo.Length.GetSizeInKB().ToString("#,###,###"), string.Join(", ", item.albums)); } Console.Write(table.ToString()); _console.WriteLine(); } string[] GetAlbums(MyMediaFileItem item) { var albums = item.relPath.Substring(0, item.relPath.LastIndexOf(item.fileInfo.Name)); if (albums.StartsWith(Path.DirectorySeparatorChar)) { albums = albums.Substring(1); } if (albums.EndsWith(Path.DirectorySeparatorChar)) { albums = albums.Substring(0, albums.Length - 1); } var myAlbums = albums.Split(Path.DirectorySeparatorChar); return(myAlbums); } //note: if we are uploading a crazy amount of data ProgressBar only supports int for ticks, so may break :/ var totalBytes = items.Sum(p => p.fileInfo.Length); if (totalBytes > int.MaxValue) { throw new Exception($"Unable to upload more than {((long)int.MaxValue).GetSizeInMB()} in one session!"); } var totalKBytes = totalBytes.GetSizeInKB(); if (!AutoConfirm && !Prompt.GetYesNo($"Hit (Y)es to upload {items.Count} files, {totalBytes.GetSizeInMB():###,###} MB...", false, ConsoleColor.Cyan)) { return(0); } else { _console.WriteLine($"Now uploading {items.Count} files, {totalBytes.GetSizeInMB():###,###} MB..."); } var dtStart = DateTime.UtcNow; var estimatedDuration = TimeSpan.FromMilliseconds(items.Count * 2_000);//set gu-estimatedDuration pbar = new ProgressBar((int)totalBytes, $"Uploading {items.Count} media item(s)...", pbarOptions) { EstimatedDuration = estimatedDuration }; //do we upload an assign to library(and albums) as we progress? //or //do we upload all and get the uploadTokens, then assign to the library(and albums) in a second step? //...which gives the user to bomb out if a file isn't successfully uploaded? var uploadedFileCount = 0; var uploadedTotalBytes = 0; foreach (var item in items) { var str = $"{item.fileInfo.Name} : 0 of {(int)item.fileInfo.Length.GetSizeInKB()} Kb"; childPBar = pbar.Spawn((int)item.fileInfo.Length, str, childPbarOptions); //todo: pass Action or Func for a callback instead of raising an event? var uploadToken = await _googlePhotosSvc.UploadMediaAsync(item.fileInfo.FullName /*, callback: child.Tick()*/); if (!string.IsNullOrWhiteSpace(uploadToken)) { item.uploadToken = uploadToken; } else { Debugger.Break(); //todo: how to handle upload failure here? } childPBar.Dispose(); uploadedFileCount++; uploadedTotalBytes += (int)item.fileInfo.Length; pbar.Tick(uploadedTotalBytes, $"Uploaded {uploadedFileCount} of {items.Count}"); //if (Interlocked.Read(ref iteration) % 25 == 0) { var tsTaken = DateTime.UtcNow.Subtract(dtStart).TotalMilliseconds; var timePerCombination = tsTaken / uploadedFileCount; pbar.EstimatedDuration = TimeSpan.FromMilliseconds((items.Count - uploadedFileCount) * timePerCombination); } } pbar.Dispose(); //album duplicate checking needs to happen first var requiredAlbumTitles = items.SelectMany(p => p.albums).Distinct(StringComparer.OrdinalIgnoreCase).Where(p => !string.IsNullOrWhiteSpace(p)).ToList(); //allAlbums = await _diskCacheSvc.GetAsync($"albums.json", () => _googlePhotosSvc.GetAlbumsAsync()); allAlbums = await _googlePhotosSvc.GetAlbumsAsync(); if (!requiredAlbumTitles.IsNullOrEmpty()) { DoDuplicateAlbumsExist(); } var dAlbums = await GetOrCreateAlbums(); if (dAlbums is null) { return(1); } _console.Write($"Adding {items.Count} media item(s) to your library..."); var uploadItems = items.Select(p => (p.uploadToken, p.fileInfo.Name)).ToList(); var res = await _googlePhotosSvc.AddMediaItemsAsync(uploadItems); if (res is object) { _console.WriteLine($" done! :)"); //iterate over results and assign the MediaItem object to our collection foreach (var newMediaItem in res.newMediaItemResults) { var item = items.FirstOrDefault(p => p.uploadToken == newMediaItem.uploadToken); if (item is null) { throw new Exception("could this happen?"); } if (newMediaItem.status is object && newMediaItem.status.message == "Success") { item.mediaItem = newMediaItem.mediaItem; } else { Debugger.Break(); //todo: handle error? } } //todo: delete local files (if required) //todo: delete empty folders? if (deleteLocal) { foreach (var item in items.Where(p => p.mediaItem is object)) { _console.Write($"Deleting '{item.fileInfo.FullName}'..."); File.Delete(item.fileInfo.FullName);//todo: try...catch here? _console.WriteLine($" deleted!"); } } if (dAlbums.Count > 0) { _console.WriteLine($"Adding media item(s) to albums..."); //todo: put progress bar here? var table = new Table("Album Name", "Status") { Config = TableConfiguration.Markdown() }; foreach (var kvp in dAlbums) { var ids = items.Where(p => p.albums.Contains(kvp.Value.title, StringComparer.OrdinalIgnoreCase)).Select(p => p.mediaItem.id).ToList(); if (await _googlePhotosSvc.AddMediaItemsToAlbumAsync(kvp.Value.id, ids)) { table.AddRow(kvp.Value.title, $"{ids.Count} media item(s) added"); } else { Debugger.Break(); } } Console.Write(table.ToString()); _console.WriteLine(); } _console.WriteLine($"Upload completed, exiting."); } else { _console.WriteLine($" failed :("); } //todo: now handle albums //todo: do we add media items to local cache here? return(0); bool DoDuplicateAlbumsExist() { var duplicateAlbumsByTitle = GetAlbumDuplicates(allAlbums); //album titles in google photos don't need to be unique, but we can't assign photos to an existing album //if duplicate titles exist that match one of our required album titles... if (duplicateAlbumsByTitle.Count > 0 && duplicateAlbumsByTitle.Any(p => requiredAlbumTitles.Contains(p.title, StringComparer.OrdinalIgnoreCase))) { _console.WriteLine($"Duplicate album titles present, unable to assign media item(s) to albums."); foreach (var album in duplicateAlbumsByTitle) { _console.WriteLine($"{album.title}"); } _console.WriteLine($"Please rename or merge the above albums to continue."); return(false); } return(true); } async Task <Dictionary <string, Album> > GetOrCreateAlbums() { //great there are no duplicate titles, lets get/create the missing albums var d = new Dictionary <string, Album>(); foreach (var title in requiredAlbumTitles) { var album = allAlbums.FirstOrDefault(p => p.title.Equals(title, StringComparison.OrdinalIgnoreCase)); if (album is null) { album = await _googlePhotosSvc.CreateAlbumAsync(title); } d.Add(title, album); } return(d); } }