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();
        }
Example #2
0
        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();
        }
Example #3
0
        /// <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());
        }
Example #5
0
        /// <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);
        }
Example #8
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);
        }
    }