Image Uploads for Dev.to with Dropbox
Tags: bash, upload, dropbox, automation
Published: 2020-11-09 15:57:50

---
title: Image Uploads for Dev.to with Dropbox
published: true
series: Publishing workflow
tags: bash, upload, dropbox, automation
---

My publishing workflow is more or less automated. The only point is uploading images for linking and displaying. The `dev.to` API doesn't support uploading images yet. To automate this part I decide to use Dropbox. Dropbox has an API which is more or less simple and is commonly used.
But before we can upload our images, we have to create our own `Dropbox App`. With your own Dropbox App you have full control to upload your images, and get the image links for referencing in your blog entries. 


## Create Dropbox App for preparation
To create a Dropbox App go to [Create App](https://www.dropbox.com/developers/apps/create)

![Image_Upload_For_devto_with_dropbox_-_Create_new_Dropbox_App.png](https://www.dropbox.com/s/hsszelslojzjnrh/Image_Upload_For_devto_with_dropbox_-_Create_new_Dropbox_App.png?raw=1)
 
After the App creation, we have to adjust the permissions. Go to the Dropbox App overview and click on your newly created App:

![Image_Upload_For_devto_with_dropbox_-_Dropbox_App_overview.png](https://www.dropbox.com/s/vho14lxce1m3vi5/Image_Upload_For_devto_with_dropbox_-_Dropbox_App_overview.png?raw=1)

The App permissions need following rights:
![Image_Upload_For_devto_with_dropbox_-_App_permissions.png](https://www.dropbox.com/s/t3yp4sh759c9tu0/Image_Upload_For_devto_with_dropbox_-_App_permissions.png?raw=1)

We need also an access token for our script. In `App settings` you can generate an access token without expiring date: 

![Image_Upload_For_devto_with_dropbox_-_Dropbox_App_Generate_Token.png](https://www.dropbox.com/s/lzax7ru7s75i9qa/Image_Upload_For_devto_with_dropbox_-_Dropbox_App_Generate_Token.png?raw=1)

Save your access token for later use.

We finished the preparation on the Dropbox side.

## Using the Dropbox API

### Uploading images to Dropbox
We starting to discover the Dropbox API in the http section [here](https://www.dropbox.com/developers/documentation/http/documentation)

For now I am only interested in [Content-upload](https://www.dropbox.com/developers/documentation/http/documentation#files-upload). I'm following this example but adapting the path:
```bash
curl -X POST https://content.dropboxapi.com/2/files/upload \
    --header "Authorization: Bearer <access Token> " \
    --header "Dropbox-API-Arg: {\"path\": \"/Images/TestImage.png\",\"mode\": \"add\",\"autorename\": true,\"mute\": false,\"strict_conflict\": false}" \
    --header "Content-Type: application/octet-stream" \
    --data-binary @"/home/user/path/to/image.png"
```

After the first test run you will find your uploads in `Dropbox/Apps/[yourAppname]/Images`.

Now we need the `sharing link` for this image. This is possible via:

### Create sharing links

```bash
curl -X POST https://api.dropboxapi.com/2/sharing/create_sharing_link_with_settings \
    --header "Authorization: Bearer <access Token>" \
    --header "Content-Type: application/json" \
    --data "{\"path\": \"/Prime_Numbers.txt\",\"settings\": {\"requested_visibility\": \"public\",\"audience\": \"public\",\"access\": \"viewer\"}}"
```

We can expect following return:
```javascript
{
    ".tag": "file",
    "url": "https://www.dropbox.com/s/2sn712vy1ovegw8/Prime_Numbers.txt?dl=0",
    "name": "Prime_Numbers.txt",
    "link_permissions": {
        "can_revoke": false,
        "resolved_visibility": {
            ".tag": "public"
        },
        "revoke_failure_reason": {
            ".tag": "owner_only"
        }
    },
    "client_modified": "2015-05-12T15:50:38Z",
    "server_modified": "2015-05-12T15:50:38Z",
    "rev": "a1c10ce0dd78",
    "size": 7212,
    "id": "id:a4ayc_80_OEAAAAAAAAAXw",
    "path_lower": "/homework/math/prime_numbers.txt",
    "team_member_info": {
        "team_info": {
            "id": "dbtid:AAFdgehTzw7WlXhZJsbGCLePe8RvQGYDr-I",
            "name": "Acme, Inc."
        },
        "display_name": "Roger Rabbit",
        "member_id": "dbmid:abcd1234"
    }
}
```

### Fetch the sharing link

Theoretically we can use the output of the first response to get the sharing link. But if we want to use this script twice, you get a different response, with the message that the images is already exits. For This case we need a third API call just to fetch the sharing link.

The response from `https://api.dropboxapi.com/2/sharing/list_shared_links` will be piped to [jq](https://stedolan.github.io/jq/) with some `sed` magic we replace the parameter `dl=0` with `raw=1` to use it in a markdown image link.

```bash
    # Get the shared image url,
    # get the url value from response with jq '.url'
    # replaces link parameter dl=0 to raw=1
    # removed " from string
    url=$(curl -X POST https://api.dropboxapi.com/2/sharing/list_shared_links \
        --header "Authorization: Bearer $dropboxApiToken" \
        --header "Content-Type: application/json" \
        --data "{\"path\": \"/Images/$imageName\"}" | jq '.links[0].url' | sed -e "s/dl=0/raw=1/g" -e "s/\"//g")

```

The last point of automation is to replace the links in the markdown files. This is also something what we can do with `sed`. 
After some try and errors, I come up with this little script.

```bash

#!/bin/bash

#grep all images in content and read as array
readarray -t content < <(grep "^\!\[.*\]" "$1")

for i in "${content[@]}"
do : 
    #Get image Name in between [ and ]
    imageName=$(echo $i | sed -e"s/\!\[//g" -e "s/\]//g")

    # Upload all images
    curl -X POST https://content.dropboxapi.com/2/files/upload \
        --header "Authorization: Bearer $dropboxApiToken" \
        --header "Dropbox-API-Arg: {\"path\": \"/Images/$imageName\",\"mode\": \"add\",\"autorename\": true,\"mute\": false,\"strict_conflict\": false}" \
        --header "Content-Type: application/octet-stream" \
        --data-binary @"/home/maren/development/blog/content/images/$imageName"

    # Create sharing link
    curl -X POST https://api.dropboxapi.com/2/sharing/create_shared_link_with_settings \
        --header "Authorization: Bearer $dropboxApiToken" \
        --header "Content-Type: application/json" \
        --data "{\"path\": \"/Images/$imageName\",\"settings\": {\"requested_visibility\": \"public\",\"audience\": \"public\",\"access\": \"viewer\"}}"


    # Get the sharing image url,
    # get the url value from response with jq '.url'
    # replaces link parameter dl=0 to raw=1
    # removed " from string
    url=$(curl -X POST https://api.dropboxapi.com/2/sharing/list_shared_links \
        --header "Authorization: Bearer $dropboxApiToken" \
        --header "Content-Type: application/json" \
        --data "{\"path\": \"/Images/$imageName\"}" | jq '.links[0].url' | sed -e "s/dl=0/raw=1/g" -e "s/\"//g")

    # add url to image line
    echo -e "=== REPLACE image tags $imageName in $1 ==="
    sed -i "s#\[$imageName\]#\[$imageName\]\($url\)#g" "$1"

done

```

To use this script we have to follow some rules in our markdown. 
We use the image tag as usual `![Image_name_without_spaces.png]` but we can left out the parentheses, the filename should not contain spaces and the image tag should be at the beginning of a line. This script will add the missing parentheses with the Dropbox image links.
In addition the images should be in a specific directory for convenience - in my case it is located in `/home/maren/development/blog/content/images` 

The last step is to merge my old publishing script together. For better readability I split the script in multiple functions. You can find this script as gist [here](https://gist.github.com/mafflerbach/bdb16ebba3d3705918b4c9f322212d28)

Now the process is completely automated and flawless controlled via command line.