Intelerad has developed something called “nuage Patient Portal”, which is used by many clinics to let patients download their scans. It’s an excellent service, especially if you want to have backups of all of your own health records. But it (or at least the version used by my clinic) does have a flaw: it’s cumbersome to download all the images.

It is possible to download an image set as a video, but the resulting file seems to be broken. Popular video software like MPV and VLC were unable to play the files smoothly, and using FFmpeg to extract frames from the video resulted in an incomplete set, so I’m pretty sure the video files are not standards compliant. It is also possible to download each image of a set individually, but this requires two mouse clicks and then scrolling or pressing the down button to get to the next image. Doing this for more than 1,000 images would be a massive chore, not to mention error prone. So I looked around for a way to easily automate this (ideally) one-off process. I tried a few solutions, but none of them seemed to work well, so I won’t mention them here.

After a few hours I learned about ydotool, a generic desktop automation tool for Linux. It did the trick, by providing simple commands like ydotool click 0xC0 to left click and release, ydotool mousemove --xpos 0 --ypos -50 to move the mouse pointer down, and ydotool key 108:1 108:0 to press and immediately release the down arrow.

Prerequisites

  • Bash
  • ydotool

Code

#!/usr/bin/env bash

set -o errexit -o nounset

if (($# < 1)) || (($# > 2)); then
    cat >&2 << EOF
$0: Download nuage image series, since they don't provide a convenient way of doing that.

Tested only with Firefox on Linux.

Usage:

1. Configure your browser to download to a directory without prompting, and to disable the pop-over when downloads finish (Go to $(about:config) then turn $(browser.download.alwaysOpenPanel) to $(false)).
2. Log into your clinic's nuage patient portal.
3. Go to the first image in the series you want to download.
4. Note the number of images in the top right, for use in step 8.
5. Open up a terminal side by side with the browser, making sure not to obstruct the browser window.
6. \`cd\` into your browser download directory, for example \`~/download\`. This directory should ideally be empty to avoid overwriting any existing files.
7. Move the mouse pointer so it hovers above the middle of the download icon, but don't click it.
8. Run \`$0 IMAGE_COUNT\`. For example, \`$0 100\` will try to download 100 images.

Troubleshooting:

When this gets stuck because the website randomly decides to start auto-playing an image series:

1. Pause.
2. Go back to the last image you managed to download.
3. Use \`$0 IMAGE_COUNT LAST_IMAGE_NUMBER\` to resume.
EOF
    exit 2
fi

image_count="$1"
image_number="${2-1}"

readonly pixels_from_download_button_to_link=40

# Focus the browser window
ydotool click 0xC0
ydotool click 0xC0

while (("$image_number" <= "$image_count")); do
    while ! compgen -G "./* ${image_number}.png" > /dev/null; do
        ydotool click 0xC0                                                        # Left mouse button on download icon
        sleep 0.3s                                                                # Wait for menu to appear
        ydotool mousemove --xpos 0 --ypos "$pixels_from_download_button_to_link"  # Move down to "Download current image"
        ydotool click 0xC0                                                        # Left mouse button on "Download current image"
        sleep 0.1s                                                                # Wait for menu to disappear
        ydotool mousemove --xpos 0 --ypos -"$pixels_from_download_button_to_link" # Move back up to download icon
    done
    ydotool key 108:1 108:0 # Press and release down arrow to go to next image

    # Clean up extra downloads
    mapfile -t extra_files < <(compgen -G "./* ${image_number}([1-9]).png")
    if (("${#extra_files[@]}" != 0)); then
        rm --verbose "${extra_files[@]}"
    fi

    ((++image_number))
done

Use

  1. Put the code above into a file such as download.bash.
  2. Make the file executable.
  3. Run the file and follow the instructions printed on screen.