DEV Community

loading...

Image Uploads for Dev.to with Dropbox

mafflerbach
・4 min read

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

Image_Upload_For_devto_with_dropbox_-_Create_new_Dropbox_App.png

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

The App permissions need following rights:
Image_Upload_For_devto_with_dropbox_-_App_permissions.png

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

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

For now I am only interested in Content-upload. I'm following this example but adapting the path:

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"
Enter fullscreen mode Exit fullscreen mode

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

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\"}}"
Enter fullscreen mode Exit fullscreen mode

We can expect following return:

{
    ".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"
    }
}
Enter fullscreen mode Exit fullscreen mode

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 with some sed magic we replace the parameter dl=0 with raw=1 to use it in a markdown image link.

    # 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")

Enter fullscreen mode Exit fullscreen mode

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.


#!/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

Enter fullscreen mode Exit fullscreen mode

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

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

Discussion (2)

Collapse
mrrcollins profile image
Ryan Collins

Another option is B2 storage from Backblaze. You get 10GB for free, and it's really easy to upload pictures. That's what I use for images for my static website.

I have a script that uses imagemagick to resize a picture into a few standard formats and then uploads all of them to B2. Maybe I should write an article about it... 😁

Collapse
mafflerbach profile image
mafflerbach Author

Why not, i just searched for a data hoster which is commonly used and provide an api. The idea is quite generic.
I think watermarking with imagemagick is something interesting as well.