cookbook.geuer-pollmann.de
  • Introduction
  • Command line utilities
    • bash scripting
    • cURL command line utility
    • ffmpeg - Processing Media
    • JOSE from the command line
    • jq
    • Misc. command line tools
    • Zettelkasten / Markdown
  • Azure
    • Logging in to Azure
    • Working with the REST API
    • Tracing HTTP requests with Fiddler
    • Upload a file from bash
    • Azure CLI
    • terraform
    • Azure Logic Apps
    • Azure Web Apps
    • Azure Python code snippets
    • SSH keys in ARM
    • Minimal "Azure AD Workload identity federation"
    • Federated credentials from GitHub and GitLab pipelines to Azure
    • Azure Marketplace Metered Billing- Picking the correct ID when submitting usage events
    • Manually submitting values to the Azure Metering API
    • How can a publisher/ISV access the data plane of an Azure managed application?
    • The checkZonePeers API: Is your availability zone "1" equal to my "1"?
    • Token authentication with "Azure Verizon Premium CDN"
    • Getting the right storage container name in a Bicep template
    • Event-sourcing into working memory to improve data access latency
    • Postgrex on Azure - Connecting to Azure PostgreSQL from Elixir
  • Productivity
    • Excel
    • Desktop Setup
    • Time handling and Scheduling
    • Elgato from the shell
    • Typora
Powered by GitBook
On this page
Edit on GitHub
  1. Productivity

Typora

PreviousElgato from the shell

Last updated 3 years ago

I'm a big fan of the markdown editor, as it has a nice WYSIWYG experience. They also support to a storage backend of your choice.

This sample here is a small uploader CLI for Azure bblob storage. Essentially, you need to set a TYPORA_IMAGE_UPLOAD_AZURE_CONNECTION environment variable, and ensure you have a container named typoraimages.

namespace TyporaUploaderAzure
{
    using System;
    using System.IO;
    using System.Linq;
    using System.Security.Cryptography;
    using System.Threading.Tasks;
    using Azure.Storage.Blobs.Models;
    using SimpleBase;

    class Program
    {
        // https://support.typora.io/Upload-Image/
        static async Task Main(string[] args)
        {
            var connectionString = Environment.GetEnvironmentVariable("TYPORA_IMAGE_UPLOAD_AZURE_CONNECTION");
            var serviceClient = new Azure.Storage.Blobs.BlobServiceClient(connectionString: connectionString);
            var containerClient = serviceClient.GetBlobContainerClient(blobContainerName: "typoraimages");
            // await containerClient.CreateIfNotExistsAsync(Azure.Storage.Blobs.Models.PublicAccessType.Blob);

            var prefix = DateTime.Now.ToString("yyyy/MM/dd/HH/mm");

            var tasks = args.Select(async filename =>
            {
                var fi = new FileInfo(filename);
                var bytes = await File.ReadAllBytesAsync(path: fi.FullName);
                using var hashAlgo = MD5.Create();
                using var reader = fi.OpenRead();

                var hash = hashAlgo.ComputeHash(bytes);
                var hashBase32 = Base32.Crockford.Encode(hash);
                var fileWithoutExtension = fi.Name.Substring(0, fi.Name.Length - fi.Extension.Length);
                var blobName = $"{prefix}/{fileWithoutExtension}----{hashBase32}{fi.Extension}";
                var blobClient = containerClient.GetBlobClient(blobName);

                string mimeType(string extension) => extension switch
                {
                    ".png" => "image/png",
                    ".jpeg" => "image/jpeg",
                    ".jpg" => "image/jpeg",
                    _ => "application/octet-stream",
                };

                if (!await blobClient.ExistsAsync())
                {
                    using var ms = new MemoryStream(bytes);
                    await blobClient.UploadAsync(ms);

                    var headers = new BlobHttpHeaders
                    {
                        ContentType = mimeType(fi.Extension),
                        ContentHash = hash,
                        CacheControl = "max-age=31536000",
                    };

                    await blobClient.SetHttpHeadersAsync(headers);
                }

                return blobClient.Uri.AbsoluteUri;
            });

            await Task.WhenAll(tasks);

            tasks
                .Select(t => t.Result)
                .ToList()
                .ForEach(Console.WriteLine);
        }
    }
}
Typora
custom image uploads