See someone using Dropbox backup site data, so today also tried, remember a python script, this is a bash script, using the Dropbox API to upload the download, very convenient, the script address is dropbox-uploader/ Dropbox_uploader.sh at Master Andreafabrizi/dropbox-uploader GitHub, thank the author for sharing this script.
You can download dropbox_uploader.sh to git, address: https://github.com/andreafabrizi/Dropbox-Uploader
Alternatively, you can copy the code directly, save it as a dropbox_uploader.sh, and note that copying is best copied to a text editor, like notepad++.
#!/usr/bin/env bash
#
# Dropbox Uploader
#
# Copyright (C) 2010-2014 Andrea Fabrizi <andrea.fabrizi@gmail.com>
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#
#Default configuration file
CONFIG_FILE=~/.dropbox_uploader
#Default chunk size in Mb for the upload process
#It is recommended to increase this value only if you have enough free space on your /tmp partition
#Lower values may increase the number of http requests
CHUNK_SIZE=4
#Curl location
#If not set, curl will be searched into the $PATH
#CURL_BIN="/usr/bin/curl"
#Default values
TMP_DIR="/tmp"
DEBUG=0
QUIET=0
SHOW_PROGRESSBAR=0
SKIP_EXISTING_FILES=0
ERROR_STATUS=0
#Don't edit these...
API_REQUEST_TOKEN_URL="https://api.dropbox.com/1/oauth/request_token"
API_USER_AUTH_URL="https://www2.dropbox.com/1/oauth/authorize"
API_ACCESS_TOKEN_URL="https://api.dropbox.com/1/oauth/access_token"
API_CHUNKED_UPLOAD_URL="https://api-content.dropbox.com/1/chunked_upload"
API_CHUNKED_UPLOAD_COMMIT_URL="https://api-content.dropbox.com/1/commit_chunked_upload"
API_UPLOAD_URL="https://api-content.dropbox.com/1/files_put"
API_DOWNLOAD_URL="https://api-content.dropbox.com/1/files"
API_DELETE_URL="https://api.dropbox.com/1/fileops/delete"
API_MOVE_URL="https://api.dropbox.com/1/fileops/move"
API_COPY_URL="https://api.dropbox.com/1/fileops/copy"
API_METADATA_URL="https://api.dropbox.com/1/metadata"
API_INFO_URL="https://api.dropbox.com/1/account/info"
API_MKDIR_URL="https://api.dropbox.com/1/fileops/create_folder"
API_SHARES_URL="https://api.dropbox.com/1/shares"
APP_CREATE_URL="https://www2.dropbox.com/developers/apps"
RESPONSE_FILE="$TMP_DIR/du_resp_$RANDOM"
CHUNK_FILE="$TMP_DIR/du_chunk_$RANDOM"
TEMP_FILE="$TMP_DIR/du_tmp_$RANDOM"
BIN_DEPS="sed basename date grep stat dd mkdir"
VERSION="0.14"
umask 077
#Check the shell
if [ -z "$BASH_VERSION" ]; then
echo -e "Error: this script requires the BASH shell!"
exit 1
fi
shopt -s nullglob #Bash allows filename patterns which match no files to expand to a null string, rather than themselves
shopt -s dotglob #Bash includes filenames beginning with a "." in the results of filename expansion
#Look for optional config file parameter
while getopts ":qpskdf:" opt; do
case $opt in
f)
CONFIG_FILE=$OPTARG
;;
d)
DEBUG=1
;;
q)
QUIET=1
;;
p)
SHOW_PROGRESSBAR=1
;;
k)
CURL_ACCEPT_CERTIFICATES="-k"
;;
s)
SKIP_EXISTING_FILES=1
;;
\?)
echo "Invalid option: -$OPTARG" >&2
exit 1
;;
:)
echo "Option -$OPTARG requires an argument." >&2
exit 1
;;
esac
done
if [[ $DEBUG != 0 ]]; then
echo $VERSION
set -x
RESPONSE_FILE="$TMP_DIR/du_resp_debug"
fi
if [[ $CURL_BIN == "" ]]; then
BIN_DEPS="$BIN_DEPS curl"
CURL_BIN="curl"
fi
#Dependencies check
which $BIN_DEPS > /dev/null
if [[ $? != 0 ]]; then
for i in $BIN_DEPS; do
which $i > /dev/null ||
NOT_FOUND="$i $NOT_FOUND"
done
echo -e "Error: Required program could not be found: $NOT_FOUND"
exit 1
fi
#Check if readlink is installed and supports the -m option
#It's not necessary, so no problem if it's not installed
which readlink > /dev/null
if [[ $? == 0 && $(readlink -m "//test" 2> /dev/null) == "/test" ]]; then
HAVE_READLINK=1
else
HAVE_READLINK=0
fi
#Forcing to use the builtin printf, if it's present, because it's better
#otherwise the external printf program will be used
#Note that the external printf command can cause character encoding issues!
builtin printf "" 2> /dev/null
if [[ $? == 0 ]]; then
PRINTF="builtin printf"
PRINTF_OPT="-v o"
else
PRINTF=$(which printf)
if [[ $? != 0 ]]; then
echo -e "Error: Required program could not be found: printf"
fi
PRINTF_OPT=""
fi
#Print the message based on $QUIET variable
function print
{
if [[ $QUIET == 0 ]]; then
echo -ne "$1";
fi
}
#Returns unix timestamp
function utime
{
echo $(date +%s)
}
#Remove temporary files
function remove_temp_files
{
if [[ $DEBUG == 0 ]]; then
rm -fr "$RESPONSE_FILE"
rm -fr "$CHUNK_FILE"
rm -fr "$TEMP_FILE"
fi
}
#Returns the file size in bytes
# generic GNU Linux: linux-gnu
# windows cygwin: cygwin
# raspberry pi: linux-gnueabihf
# macosx: darwin10.0
# freebsd: FreeBSD
# qnap: linux-gnueabi
# iOS: darwin9
function file_size
{
#Some embedded linux devices
if [[ $OSTYPE == "linux-gnueabi" || $OSTYPE == "linux-gnu" ]]; then
stat -c "%s" "$1"
return
#Generic Unix
elif [[ ${OSTYPE:0:5} == "linux" || $OSTYPE == "cygwin" || ${OSTYPE:0:7} == "solaris" ]]; then
stat --format="%s" "$1"
return
#BSD, OSX and other OSs
else
stat -f "%z" "$1"
return
fi
}
#Usage
function usage
{
echo -e "Dropbox Uploader v$VERSION"
echo -e "Andrea Fabrizi - andrea.fabrizi@gmail.com\n"
echo -e "Usage: $0 COMMAND [PARAMETERS]..."
echo -e "\nCommands:"
echo -e "\t upload <LOCAL_FILE/DIR ...> <REMOTE_FILE/DIR>"
echo -e "\t download <REMOTE_FILE/DIR> [LOCAL_FILE/DIR]"
echo -e "\t delete <REMOTE_FILE/DIR>"
echo -e "\t move <REMOTE_FILE/DIR> <REMOTE_FILE/DIR>"
echo -e "\t copy <REMOTE_FILE/DIR> <REMOTE_FILE/DIR>"
echo -e "\t mkdir <REMOTE_DIR>"
echo -e "\t list [REMOTE_DIR]"
echo -e "\t share <REMOTE_FILE>"
echo -e "\t info"
echo -e "\t unlink"
echo -e "\nOptional parameters:"
echo -e "\t-f <FILENAME> Load the configuration file from a specific file"
echo -e "\t-s Skip already existing files when download/upload. Default: Overwrite"
echo -e "\t-d Enable DEBUG mode"
echo -e "\t-q Quiet mode. Don't show messages"
echo -e "\t-p Show cURL progress meter"
echo -e "\t-k Doesn't check for SSL certificates (insecure)"
echo -en "\nFor more info and examples, please see the README file.\n\n"
remove_temp_files
exit 1
}
#Check the curl exit code
function check_http_response
{
CODE=$?
#Checking curl exit code
case $CODE in
#OK
0)
;;
#Proxy error
5)
print "\nError: Couldn't resolve proxy. The given proxy host could not be resolved.\n"
remove_temp_files
exit 1
;;
#Missing CA certificates
60|58)
print "\nError: cURL is not able to performs peer SSL certificate verification.\n"
print "Please, install the default ca-certificates bundle.\n"
print "To do this in a Debian/Ubuntu based system, try:\n"
print " sudo apt-get install ca-certificates\n\n"
print "If the problem persists, try to use the -k option (insecure).\n"
remove_temp_files
exit 1
;;
6)
print "\nError: Couldn't resolve host.\n"
remove_temp_files
exit 1
;;
7)
print "\nError: Couldn't connect to host.\n"
remove_temp_files
exit 1
;;
esac
#Checking response file for generic errors
if grep -q "HTTP/1.1 400" "$RESPONSE_FILE"; then
ERROR_MSG=$(sed -n -e 's/{"error": "\([^"]*\)"}/\1/p' "$RESPONSE_FILE")
case $ERROR_MSG in
*access?attempt?failed?because?this?app?is?not?configured?to?have*)
echo -e "\nError: The Permission type/Access level configured doesn't match the DropBox App settings!\nPlease run \"$0 unlink\" and try again."
exit 1
;;
esac
fi
}
#Urlencode
function urlencode
{
local string="${1}"
local strlen=${#string}
local encoded=""
for (( pos=0 ; pos<strlen ; pos++ )); do
c=${string:$pos:1}
case "$c" in
[-_.~a-zA-Z0-9] ) o="${c}" ;;
* ) $PRINTF $PRINTF_OPT '%%%02x' "'$c"
esac
encoded+="${o}"
done
echo "$encoded"
}
function normalize_path
{
path=$(echo -e "$1")
if [[ $HAVE_READLINK == 1 ]]; then
readlink -m "$path"
else
echo "$path"
fi
}
#Check if it's a file or directory
#Returns FILE/DIR/ERR
function db_stat
{
local FILE=$(normalize_path "$1")
#Checking if it's a file or a directory
$CURL_BIN $CURL_ACCEPT_CERTIFICATES -s --show-error --globoff -i -o "$RESPONSE_FILE" "$API_METADATA_URL/$ACCESS_LEVEL/$(urlencode "$FILE")?oauth_consumer_key=$APPKEY&oauth_token=$OAUTH_ACCESS_TOKEN&oauth_signature_method=PLAINTEXT&oauth_signature=$APPSECRET%26$OAUTH_ACCESS_TOKEN_SECRET&oauth_timestamp=$(utime)&oauth_nonce=$RANDOM" 2> /dev/null
check_http_response
#Even if the file/dir has been deleted from DropBox we receive a 200 OK response
#So we must check if the file exists or if it has been deleted
if grep -q "\"is_deleted\":" "$RESPONSE_FILE"; then
local IS_DELETED=$(sed -n 's/.*"is_deleted":.\([^,]*\).*/\1/p' "$RESPONSE_FILE")
else
local IS_DELETED="false"
fi
#Exits...
grep -q "^HTTP/1.1 200 OK" "$RESPONSE_FILE"
if [[ $? == 0 && $IS_DELETED != "true" ]]; then
local IS_DIR=$(sed -n 's/^\(.*\)\"contents":.\[.*/\1/p' "$RESPONSE_FILE")
#It's a directory
if [[ $IS_DIR != "" ]]; then
echo "DIR"
#It's a file
else
echo "FILE"
fi
#Doesn't exists
else
echo "ERR"
fi
}
#Generic upload wrapper around db_upload_file and db_upload_dir functions
#$1 = Local source file/dir
#$2 = Remote destination file/dir
function db_upload
{
local SRC=$(normalize_path "$1")
local DST=$(normalize_path "$2")
#Checking if the file/dir exists
if [[ ! -e $SRC && ! -d $SRC ]]; then
print " > No such file or directory: $SRC\n"
ERROR_STATUS=1
return
fi
#Checking if the file/dir has read permissions
if [[ ! -r $SRC ]]; then
print " > Error reading file $SRC: permission denied\n"
ERROR_STATUS=1
return
fi
#Checking if DST it's a folder or if it doesn' exists (in this case will be the destination name)
TYPE=$(db_stat "$DST")
if [[ $TYPE == "DIR" ]]; then
local filename=$(basename "$SRC")
DST="$DST/$filename"
fi
#It's a directory
if [[ -d $SRC ]]; then
db_upload_dir "$SRC" "$DST"
#It's a file
elif [[ -e $SRC ]]; then
db_upload_file "$SRC" "$DST"
#Unsupported object...
else
print " > Skipping not regular file \"$SRC\"\n"
fi
}
#Generic upload wrapper around db_chunked_upload_file and db_simple_upload_file
#The final upload function will be choosen based on the file size
#$1 = Local source file
#$2 = Remote destination file
function db_upload_file
{
local FILE_SRC=$(normalize_path "$1")
local FILE_DST=$(normalize_path "$2")
shopt -s nocasematch
#Checking not allowed file names
basefile_dst=$(basename "$FILE_DST")
if [[ $basefile_dst == "thumbs.db" || \
$basefile_dst == "desktop.ini" || \
$basefile_dst == ".ds_store" || \
$basefile_dst == "icon\r" || \
$basefile_dst == ".dropbox" || \
$basefile_dst == ".dropbox.attr" \
]]; then
print " > Skipping not allowed file name \"$FILE_DST\"\n"
return
fi
shopt -u nocasematch
#Checking file size
FILE_SIZE=$(file_size "$FILE_SRC")
#Checking if the file already exists
TYPE=$(db_stat "$FILE_DST")
if [[ $TYPE != "ERR" && $SKIP_EXISTING_FILES == 1 ]]; then
print " > Skipping already existing file \"$FILE_DST\"\n"
return
fi
if [[ $FILE_SIZE -gt 157286000 ]]; then
#If the file is greater than 150Mb, the chunked_upload API will be used
db_chunked_upload_file "$FILE_SRC" "$FILE_DST"
else
db_simple_upload_file "$FILE_SRC" "$FILE_DST"
fi
}
#Simple file upload
#$1 = Local source file
#$2 = Remote destination file
function db_simple_upload_file
{
local FILE_SRC=$(normalize_path "$1")
local FILE_DST=$(normalize_path "$2")
if [[ $SHOW_PROGRESSBAR == 1 && $QUIET == 0 ]]; then
CURL_PARAMETERS="--progress-bar"
LINE_CR="\n"
else
CURL_PARAMETERS="-s"
LINE_CR=""
fi
print " > Uploading \"$FILE_SRC\" to \"$FILE_DST\"... $LINE_CR"
$CURL_BIN $CURL_ACCEPT_CERTIFICATES $CURL_PARAMETERS -i --globoff -o "$RESPONSE_FILE" --upload-file "$FILE_SRC" "$API_UPLOAD_URL/$ACCESS_LEVEL/$(urlencode "$FILE_DST")?oauth_consumer_key=$APPKEY&oauth_token=$OAUTH_ACCESS_TOKEN&oauth_signature_method=PLAINTEXT&oauth_signature=$APPSECRET%26$OAUTH_ACCESS_TOKEN_SECRET&oauth_timestamp=$(utime)&oauth_nonce=$RANDOM"
check_http_response
#Check
if grep -q "^HTTP/1.1 200 OK" "$RESPONSE_FILE"; then
print "DONE\n"
else
print "FAILED\n"
print "An error occurred requesting /upload\n"
ERROR_STATUS=1
fi
}
#Chunked file upload
#$1 = Local source file
#$2 = Remote destination file
function db_chunked_upload_file
{
local FILE_SRC=$(normalize_path "$1")
local FILE_DST=$(normalize_path "$2")
print " > Uploading \"$FILE_SRC\" to \"$FILE_DST\""
local FILE_SIZE=$(file_size "$FILE_SRC")
local OFFSET=0
local UPLOAD_ID=""
local UPLOAD_ERROR=0
local CHUNK_PARAMS=""
#Uploading chunks...
while ([[ $OFFSET != $FILE_SIZE ]]); do
let OFFSET_MB=$OFFSET/1024/1024
#Create the chunk
dd if="$FILE_SRC" of="$CHUNK_FILE" bs=1048576 skip=$OFFSET_MB count=$CHUNK_SIZE 2> /dev/null
#Only for the first request these parameters are not included
if [[ $OFFSET != 0 ]]; then
CHUNK_PARAMS="upload_id=$UPLOAD_ID&offset=$OFFSET"
fi
#Uploading the chunk...
$CURL_BIN $CURL_ACCEPT_CERTIFICATES -s --show-error --globoff -i -o "$RESPONSE_FILE" --upload-file "$CHUNK_FILE" "$API_CHUNKED_UPLOAD_URL?$CHUNK_PARAMS&oauth_consumer_key=$APPKEY&oauth_token=$OAUTH_ACCESS_TOKEN&oauth_signature_method=PLAINTEXT&oauth_signature=$APPSECRET%26$OAUTH_ACCESS_TOKEN_SECRET&oauth_timestamp=$(utime)&oauth_nonce=$RANDOM" 2> /dev/null
check_http_response
#Check
if grep -q "^HTTP/1.1 200 OK" "$RESPONSE_FILE"; then
print "."
UPLOAD_ERROR=0
UPLOAD_ID=$(sed -n 's/.*"upload_id": *"*\([^"]*\)"*.*/\1/p' "$RESPONSE_FILE")
OFFSET=$(sed -n 's/.*"offset": *\([^}]*\).*/\1/p' "$RESPONSE_FILE")
else
print "*"
let UPLOAD_ERROR=$UPLOAD_ERROR+1
#On error, the upload is retried for max 3 times
if [[ $UPLOAD_ERROR -gt 2 ]]; then
print " FAILED\n"
print "An error occurred requesting /chunked_upload\n"
ERROR_STATUS=1
return
fi
fi
done
UPLOAD_ERROR=0
#Commit the upload
while (true); do
$CURL_BIN $CURL_ACCEPT_CERTIFICATES -s --show-error --globoff -i -o "$RESPONSE_FILE" --data "upload_id=$UPLOAD_ID&oauth_consumer_key=$APPKEY&oauth_token=$OAUTH_ACCESS_TOKEN&oauth_signature_method=PLAINTEXT&oauth_signature=$APPSECRET%26$OAUTH_ACCESS_TOKEN_SECRET&oauth_timestamp=$(utime)&oauth_nonce=$RANDOM" "$API_CHUNKED_UPLOAD_COMMIT_URL/$ACCESS_LEVEL/$(urlencode "$FILE_DST")" 2> /dev/null
check_http_response
#Check
if grep -q "^HTTP/1.1 200 OK" "$RESPONSE_FILE"; then
print "."
UPLOAD_ERROR=0
break
else
print "*"
let UPLOAD_ERROR=$UPLOAD_ERROR+1
#On error, the commit is retried for max 3 times
if [[ $UPLOAD_ERROR -gt 2 ]]; then
print " FAILED\n"
print "An error occurred requesting /commit_chunked_upload\n"
ERROR_STATUS=1
return
fi
fi
done
print " DONE\n"
}
#Directory upload
#$1 = Local source dir
#$2 = Remote destination dir
function db_upload_dir
{
local DIR_SRC=$(normalize_path "$1")
local DIR_DST=$(normalize_path "$2")
#Creatig remote directory
db_mkdir "$DIR_DST"
for file in "$DIR_SRC/"*; do
db_upload "$file" "$DIR_DST"
done
}
#Returns the free space on DropBox in bytes
function db_free_quota
{
$CURL_BIN $CURL_ACCEPT_CERTIFICATES -s --show-error --globoff -i -o "$RESPONSE_FILE" --data "oauth_consumer_key=$APPKEY&oauth_token=$OAUTH_ACCESS_TOKEN&oauth_signature_method=PLAINTEXT&oauth_signature=$APPSECRET%26$OAUTH_ACCESS_TOKEN_SECRET&oauth_timestamp=$(utime)&oauth_nonce=$RANDOM" "$API_INFO_URL" 2> /dev/null
check_http_response
#Check
if grep -q "^HTTP/1.1 200 OK" "$RESPONSE_FILE"; then
quota=$(sed -n 's/.*"quota": \([0-9]*\).*/\1/p' "$RESPONSE_FILE")
used=$(sed -n 's/.*"normal": \([0-9]*\).*/\1/p' "$RESPONSE_FILE")
let free_quota=$quota-$used
echo $free_quota
else
echo 0
fi
}
#Generic download wrapper
#$1 = Remote source file/dir
#$2 = Local destination file/dir
function db_download
{
local SRC=$(normalize_path "$1")
local DST=$(normalize_path "$2")
TYPE=$(db_stat "$SRC")
#It's a directory
if [[ $TYPE == "DIR" ]]; then
#If the DST folder is not specified, I assume that is the current directory
if [[ $DST == "" ]]; then
DST="."
fi
#Checking if the destination directory exists
if [[ ! -d $DST ]]; then
local basedir=""
else
local basedir=$(basename "$SRC")
fi
local DEST_DIR=$(normalize_path "$DST/$basedir")
print " > Downloading \"$SRC\" to \"$DEST_DIR\"... \n"
print " > Creating local directory \"$DEST_DIR\"... "
mkdir -p "$DEST_DIR"
#Check
if [[ $? == 0 ]]; then
print "DONE\n"
else
print "FAILED\n"
ERROR_STATUS=1
return
fi
#Extracting directory content [...]
#and replacing "}, {" with "}\n{"
#I don't like this piece of code... but seems to be the only way to do this with SED, writing a portable code...
local DIR_CONTENT=$(sed -n 's/.*: \[{\(.*\)/\1/p' "$RESPONSE_FILE" | sed 's/}, *{/}\
{/g')
#Extracting files and subfolders
TMP_DIR_CONTENT_FILE="${RESPONSE_FILE}_$RANDOM"
echo "$DIR_CONTENT" | sed -n 's/.*"path": *"\([^"]*\)",.*"is_dir": *\([^"]*\),.*/\1:\2/p' > $TMP_DIR_CONTENT_FILE
#For each entry...
while read -r line; do
local FILE=${line%:*}
local TYPE=${line#*:}
#Removing unneeded /
FILE=${FILE##*/}
if [[ $TYPE == "false" ]]; then
db_download_file "$SRC/$FILE" "$DEST_DIR/$FILE"
else
db_download "$SRC/$FILE" "$DEST_DIR"
fi
done < $TMP_DIR_CONTENT_FILE
rm -fr $TMP_DIR_CONTENT_FILE
#It's a file
elif [[ $TYPE == "FILE" ]]; then
#Checking DST
if [[ $DST == "" ]]; then
DST=$(basename "$SRC")
fi
#If the destination is a directory, the file will be download into
if [[ -d $DST ]]; then
DST="$DST/$SRC"
fi
db_download_file "$SRC" "$DST"
#Doesn't exists
else
print " > No such file or directory: $SRC\n"
ERROR_STATUS=1
return
fi
}
#Simple file download
#$1 = Remote source file
#$2 = Local destination file
function db_download_file
{
local FILE_SRC=$(normalize_path "$1")
local FILE_DST=$(normalize_path "$2")
if [[ $SHOW_PROGRESSBAR == 1 && $QUIET == 0 ]]; then
CURL_PARAMETERS="--progress-bar"
LINE_CR="\n"
else
CURL_PARAMETERS="-s"
LINE_CR=""
fi
#Checking if the file already exists
if [[ -e $FILE_DST && $SKIP_EXISTING_FILES == 1 ]]; then
print " > Skipping already existing file \"$FILE_DST\"\n"
return
fi
#Creating the empty file, that for two reasons:
#1) In this way I can check if the destination file is writable or not
#2) Curl doesn't automatically creates files with 0 bytes size
dd if=/dev/zero of="$FILE_DST" count=0 2> /dev/null
if [[ $? != 0 ]]; then
print " > Error writing file $FILE_DST: permission denied\n"
ERROR_STATUS=1
return
fi
print " > Downloading \"$FILE_SRC\" to \"$FILE_DST\"... $LINE_CR"
$CURL_BIN $CURL_ACCEPT_CERTIFICATES $CURL_PARAMETERS --globoff -D "$RESPONSE_FILE" -o "$FILE_DST" "$API_DOWNLOAD_URL/$ACCESS_LEVEL/$(urlencode "$FILE_SRC")?oauth_consumer_key=$APPKEY&oauth_token=$OAUTH_ACCESS_TOKEN&oauth_signature_method=PLAINTEXT&oauth_signature=$APPSECRET%26$OAUTH_ACCESS_TOKEN_SECRET&oauth_timestamp=$(utime)&oauth_nonce=$RANDOM"
check_http_response
#Check
if grep -q "^HTTP/1.1 200 OK" "$RESPONSE_FILE"; then
print "DONE\n"
else
print "FAILED\n"
rm -fr "$FILE_DST"
ERROR_STATUS=1
return
fi
}
#Prints account info
function db_account_info
{
print "Dropbox Uploader v$VERSION\n\n"
print " > Getting info... "
$CURL_BIN $CURL_ACCEPT_CERTIFICATES -s --show-error --globoff -i -o "$RESPONSE_FILE" --data "oauth_consumer_key=$APPKEY&oauth_token=$OAUTH_ACCESS_TOKEN&oauth_signature_method=PLAINTEXT&oauth_signature=$APPSECRET%26$OAUTH_ACCESS_TOKEN_SECRET&oauth_timestamp=$(utime)&oauth_nonce=$RANDOM" "$API_INFO_URL" 2> /dev/null
check_http_response
#Check
if grep -q "^HTTP/1.1 200 OK" "$RESPONSE_FILE"; then
name=$(sed -n 's/.*"display_name": "\([^"]*\).*/\1/p' "$RESPONSE_FILE")
echo -e "\n\nName:\t$name"
uid=$(sed -n 's/.*"uid": \([0-9]*\).*/\1/p' "$RESPONSE_FILE")
echo -e "UID:\t$uid"
email=$(sed -n 's/.*"email": "\([^"]*\).*/\1/p' "$RESPONSE_FILE")
echo -e "Email:\t$email"
quota=$(sed -n 's/.*"quota": \([0-9]*\).*/\1/p' "$RESPONSE_FILE")
let quota_mb=$quota/1024/1024
echo -e "Quota:\t$quota_mb Mb"
used=$(sed -n 's/.*"normal": \([0-9]*\).*/\1/p' "$RESPONSE_FILE")
let used_mb=$used/1024/1024
echo -e "Used:\t$used_mb Mb"
let free_mb=($quota-$used)/1024/1024
echo -e "Free:\t$free_mb Mb"
echo ""
else
print "FAILED\n"
ERROR_STATUS=1
fi
}
#Account unlink
function db_unlink
{
echo -ne "Are you sure you want unlink this script from your Dropbox account? [y/n]"
read answer
if [[ $answer == "y" ]]; then
rm -fr "$CONFIG_FILE"
echo -ne "DONE\n"
fi
}
#Delete a remote file
#$1 = Remote file to delete
function db_delete
{
local FILE_DST=$(normalize_path "$1")
print " > Deleting \"$FILE_DST\"... "
$CURL_BIN $CURL_ACCEPT_CERTIFICATES -s --show-error --globoff -i -o "$RESPONSE_FILE" --data "oauth_consumer_key=$APPKEY&oauth_token=$OAUTH_ACCESS_TOKEN&oauth_signature_method=PLAINTEXT&oauth_signature=$APPSECRET%26$OAUTH_ACCESS_TOKEN_SECRET&oauth_timestamp=$(utime)&oauth_nonce=$RANDOM&root=$ACCESS_LEVEL&path=$(urlencode "$FILE_DST")" "$API_DELETE_URL" 2> /dev/null
check_http_response
#Check
if grep -q "^HTTP/1.1 200 OK" "$RESPONSE_FILE"; then
print "DONE\n"
else
print "FAILED\n"
ERROR_STATUS=1
fi
}
#Move/Rename a remote file
#$1 = Remote file to rename or move
#$2 = New file name or location
function db_move
{
local FILE_SRC=$(normalize_path "$1")
local FILE_DST=$(normalize_path "$2")
TYPE=$(db_stat "$FILE_DST")
#If the destination it's a directory, the source will be moved into it
if [[ $TYPE == "DIR" ]]; then
local filename=$(basename "$FILE_SRC")
FILE_DST=$(normalize_path "$FILE_DST/$filename")
fi
print " > Moving \"$FILE_SRC\" to \"$FILE_DST\" ... "
$CURL_BIN $CURL_ACCEPT_CERTIFICATES -s --show-error --globoff -i -o "$RESPONSE_FILE" --data "oauth_consumer_key=$APPKEY&oauth_token=$OAUTH_ACCESS_TOKEN&oauth_signature_method=PLAINTEXT&oauth_signature=$APPSECRET%26$OAUTH_ACCESS_TOKEN_SECRET&oauth_timestamp=$(utime)&oauth_nonce=$RANDOM&root=$ACCESS_LEVEL&from_path=$(urlencode "$FILE_SRC")&to_path=$(urlencode "$FILE_DST")" "$API_MOVE_URL" 2> /dev/null
check_http_response
#Check
if grep -q "^HTTP/1.1 200 OK" "$RESPONSE_FILE"; then
print "DONE\n"
else
print "FAILED\n"
ERROR_STATUS=1
fi
}
#Copy a remote file to a remote location
#$1 = Remote file to rename or move
#$2 = New file name or location
function db_copy
{
local FILE_SRC=$(normalize_path "$1")
local FILE_DST=$(normalize_path "$2")
TYPE=$(db_stat "$FILE_DST")
#If the destination it's a directory, the source will be copied into it
if [[ $TYPE == "DIR" ]]; then
local filename=$(basename "$FILE_SRC")
FILE_DST=$(normalize_path "$FILE_DST/$filename")
fi
print " > Copying \"$FILE_SRC\" to \"$FILE_DST\" ... "
$CURL_BIN $CURL_ACCEPT_CERTIFICATES -s --show-error --globoff -i -o "$RESPONSE_FILE" --data "oauth_consumer_key=$APPKEY&oauth_token=$OAUTH_ACCESS_TOKEN&oauth_signature_method=PLAINTEXT&oauth_signature=$APPSECRET%26$OAUTH_ACCESS_TOKEN_SECRET&oauth_timestamp=$(utime)&oauth_nonce=$RANDOM&root=$ACCESS_LEVEL&from_path=$(urlencode "$FILE_SRC")&to_path=$(urlencode "$FILE_DST")" "$API_COPY_URL" 2> /dev/null
check_http_response
#Check
if grep -q "^HTTP/1.1 200 OK" "$RESPONSE_FILE"; then
print "DONE\n"
else
print "FAILED\n"
ERROR_STATUS=1
fi
}
#Create a new directory
#$1 = Remote directory to create
function db_mkdir
{
local DIR_DST=$(normalize_path "$1")
print " > Creating Directory \"$DIR_DST\"... "
$CURL_BIN $CURL_ACCEPT_CERTIFICATES -s --show-error --globoff -i -o "$RESPONSE_FILE" --data "oauth_consumer_key=$APPKEY&oauth_token=$OAUTH_ACCESS_TOKEN&oauth_signature_method=PLAINTEXT&oauth_signature=$APPSECRET%26$OAUTH_ACCESS_TOKEN_SECRET&oauth_timestamp=$(utime)&oauth_nonce=$RANDOM&root=$ACCESS_LEVEL&path=$(urlencode "$DIR_DST")" "$API_MKDIR_URL" 2> /dev/null
check_http_response
#Check
if grep -q "^HTTP/1.1 200 OK" "$RESPONSE_FILE"; then
print "DONE\n"
elif grep -q "^HTTP/1.1 403 Forbidden" "$RESPONSE_FILE"; then
print "ALREADY EXISTS\n"
else
print "FAILED\n"
ERROR_STATUS=1
fi
}
#List remote directory
#$1 = Remote directory
function db_list
{
local DIR_DST=$(normalize_path "$1")
print " > Listing \"$DIR_DST\"... "
$CURL_BIN $CURL_ACCEPT_CERTIFICATES -s --show-error --globoff -i -o "$RESPONSE_FILE" "$API_METADATA_URL/$ACCESS_LEVEL/$(urlencode "$DIR_DST")?oauth_consumer_key=$APPKEY&oauth_token=$OAUTH_ACCESS_TOKEN&oauth_signature_method=PLAINTEXT&oauth_signature=$APPSECRET%26$OAUTH_ACCESS_TOKEN_SECRET&oauth_timestamp=$(utime)&oauth_nonce=$RANDOM" 2> /dev/null
check_http_response
#Check
if grep -q "^HTTP/1.1 200 OK" "$RESPONSE_FILE"; then
local IS_DIR=$(sed -n 's/^\(.*\)\"contents":.\[.*/\1/p' "$RESPONSE_FILE")
#It's a directory
if [[ $IS_DIR != "" ]]; then
print "DONE\n"
#Extracting directory content [...]
#and replacing "}, {" with "}\n{"
#I don't like this piece of code... but seems to be the only way to do this with SED, writing a portable code...
local DIR_CONTENT=$(sed -n 's/.*: \[{\(.*\)/\1/p' "$RESPONSE_FILE" | sed 's/}, *{/}\
{/g')
#Converting escaped quotes to unicode format
echo "$DIR_CONTENT" | sed 's/\\"/\\u0022/' > "$TEMP_FILE"
#Extracting files and subfolders
rm -fr "$RESPONSE_FILE"
while read -r line; do
local FILE=$(echo "$line" | sed -n 's/.*"path": *"\([^"]*\)".*/\1/p')
local IS_DIR=$(echo "$line" | sed -n 's/.*"is_dir": *\([^,]*\).*/\1/p')
local SIZE=$(echo "$line" | sed -n 's/.*"bytes": *\([0-9]*\).*/\1/p')
echo -e "$FILE:$IS_DIR;$SIZE" >> "$RESPONSE_FILE"
done < "$TEMP_FILE"
#Looking for the biggest file size
#to calculate the padding to use
local padding=0
while read -r line; do
local FILE=${line%:*}
local META=${line##*:}
local SIZE=${META#*;}
if [[ ${#SIZE} -gt $padding ]]; then
padding=${#SIZE}
fi
done < "$RESPONSE_FILE"
#For each entry, printing directories...
while read -r line; do
local FILE=${line%:*}
local META=${line##*:}
local TYPE=${META%;*}
local SIZE=${META#*;}
#Removing unneeded /
FILE=${FILE##*/}
if [[ $TYPE != "false" ]]; then
FILE=$(echo -e "$FILE")
$PRINTF " [D] %-${padding}s %s\n" "$SIZE" "$FILE"
fi
done < "$RESPONSE_FILE"
#For each entry, printing files...
while read -r line; do
local FILE=${line%:*}
local META=${line##*:}
local TYPE=${META%;*}
local SIZE=${META#*;}
#Removing unneeded /
FILE=${FILE##*/}
if [[ $TYPE == "false" ]]; then
FILE=$(echo -e "$FILE")
$PRINTF " [F] %-${padding}s %s\n" "$SIZE" "$FILE"
fi
done < "$RESPONSE_FILE"
#It's a file
else
print "FAILED: $DIR_DST is not a directory!\n"
ERROR_STATUS=1
fi
else
print "FAILED\n"
ERROR_STATUS=1
fi
}
#Share remote file
#$1 = Remote file
function db_share
{
local FILE_DST=$(normalize_path "$1")
$CURL_BIN $CURL_ACCEPT_CERTIFICATES -s --show-error --globoff -i -o "$RESPONSE_FILE" "$API_SHARES_URL/$ACCESS_LEVEL/$(urlencode "$FILE_DST")?oauth_consumer_key=$APPKEY&oauth_token=$OAUTH_ACCESS_TOKEN&oauth_signature_method=PLAINTEXT&oauth_signature=$APPSECRET%26$OAUTH_ACCESS_TOKEN_SECRET&oauth_timestamp=$(utime)&oauth_nonce=$RANDOM&short_url=false" 2> /dev/null
check_http_response
#Check
if grep -q "^HTTP/1.1 200 OK" "$RESPONSE_FILE"; then
print " > Share link: "
echo $(sed -n 's/.*"url": "\([^"]*\).*/\1/p' "$RESPONSE_FILE")
else
print "FAILED\n"
ERROR_STATUS=1
fi
}
################
#### SETUP ####
################
#CHECKING FOR AUTH FILE
if [[ -e $CONFIG_FILE ]]; then
#Loading data... and change old format config if necesary.
source "$CONFIG_FILE" 2>/dev/null || {
sed -i'' 's/:/=/' "$CONFIG_FILE" && source "$CONFIG_FILE" 2>/dev/null
}
#Checking the loaded data
if [[ $APPKEY == "" || $APPSECRET == "" || $OAUTH_ACCESS_TOKEN_SECRET == "" || $OAUTH_ACCESS_TOKEN == "" ]]; then
echo -ne "Error loading data from $CONFIG_FILE...\n"
echo -ne "It is recommended to run $0 unlink\n"
remove_temp_files
exit 1
fi
#Back compatibility with previous Dropbox Uploader versions
if [[ $ACCESS_LEVEL == "" ]]; then
ACCESS_LEVEL="dropbox"
fi
#NEW SETUP...
else
echo -ne "\n This is the first time you run this script.\n\n"
echo -ne " 1) Open the following URL in your Browser, and log in using your account: $APP_CREATE_URL\n"
echo -ne " 2) Click on \"Create App\", then select \"Dropbox API app\"\n"
echo -ne " 3) Select \"Files and datastores\"\n"
echo -ne " 4) Now go on with the configuration, choosing the app permissions and access restrictions to your DropBox folder\n"
echo -ne " 5) Enter the \"App Name\" that you prefer (e.g. MyUploader$RANDOM$RANDOM$RANDOM)\n\n"
echo -ne " Now, click on the \"Create App\" button.\n\n"
echo -ne " When your new App is successfully created, please type the\n"
echo -ne " App Key, App Secret and the Permission type shown in the confirmation page:\n\n"
#Getting the app key and secret from the user
while (true); do
echo -n " # App key: "
read APPKEY
echo -n " # App secret: "
read APPSECRET
echo -n " # Permission type, App folder or Full Dropbox [a/f]: "
read ACCESS_LEVEL
if [[ $ACCESS_LEVEL == "a" ]]; then
ACCESS_LEVEL="sandbox"
ACCESS_MSG="App Folder"
else
ACCESS_LEVEL="dropbox"
ACCESS_MSG="Full Dropbox"
fi
echo -ne "\n > App key is $APPKEY, App secret is $APPSECRET and Access level is $ACCESS_MSG. Looks ok? [y/n]: "
read answer
if [[ $answer == "y" ]]; then
break;
fi
done
#TOKEN REQUESTS
echo -ne "\n > Token request... "
$CURL_BIN $CURL_ACCEPT_CERTIFICATES -s --show-error --globoff -i -o "$RESPONSE_FILE" --data "oauth_consumer_key=$APPKEY&oauth_signature_method=PLAINTEXT&oauth_signature=$APPSECRET%26&oauth_timestamp=$(utime)&oauth_nonce=$RANDOM" "$API_REQUEST_TOKEN_URL" 2> /dev/null
check_http_response
OAUTH_TOKEN_SECRET=$(sed -n 's/oauth_token_secret=\([a-z A-Z 0-9]*\).*/\1/p' "$RESPONSE_FILE")
OAUTH_TOKEN=$(sed -n 's/.*oauth_token=\([a-z A-Z 0-9]*\)/\1/p' "$RESPONSE_FILE")
if [[ $OAUTH_TOKEN != "" && $OAUTH_TOKEN_SECRET != "" ]]; then
echo -ne "OK\n"
else
echo -ne " FAILED\n\n Please, check your App key and secret...\n\n"
remove_temp_files
exit 1
fi
while (true); do
#USER AUTH
echo -ne "\n Please open the following URL in your browser, and allow Dropbox Uploader\n"
echo -ne " to access your DropBox folder:\n\n --> ${API_USER_AUTH_URL}?oauth_token=$OAUTH_TOKEN\n"
echo -ne "\nPress enter when done...\n"
read
#API_ACCESS_TOKEN_URL
echo -ne " > Access Token request... "
$CURL_BIN $CURL_ACCEPT_CERTIFICATES -s --show-error --globoff -i -o "$RESPONSE_FILE" --data "oauth_consumer_key=$APPKEY&oauth_token=$OAUTH_TOKEN&oauth_signature_method=PLAINTEXT&oauth_signature=$APPSECRET%26$OAUTH_TOKEN_SECRET&oauth_timestamp=$(utime)&oauth_nonce=$RANDOM" "$API_ACCESS_TOKEN_URL" 2> /dev/null
check_http_response
OAUTH_ACCESS_TOKEN_SECRET=$(sed -n 's/oauth_token_secret=\([a-z A-Z 0-9]*\)&.*/\1/p' "$RESPONSE_FILE")
OAUTH_ACCESS_TOKEN=$(sed -n 's/.*oauth_token=\([a-z A-Z 0-9]*\)&.*/\1/p' "$RESPONSE_FILE")
OAUTH_ACCESS_UID=$(sed -n 's/.*uid=\([0-9]*\)/\1/p' "$RESPONSE_FILE")
if [[ $OAUTH_ACCESS_TOKEN != "" && $OAUTH_ACCESS_TOKEN_SECRET != "" && $OAUTH_ACCESS_UID != "" ]]; then
echo -ne "OK\n"
#Saving data in new format, compatible with source command.
echo "APPKEY=$APPKEY" > "$CONFIG_FILE"
echo "APPSECRET=$APPSECRET" >> "$CONFIG_FILE"
echo "ACCESS_LEVEL=$ACCESS_LEVEL" >> "$CONFIG_FILE"
echo "OAUTH_ACCESS_TOKEN=$OAUTH_ACCESS_TOKEN" >> "$CONFIG_FILE"
echo "OAUTH_ACCESS_TOKEN_SECRET=$OAUTH_ACCESS_TOKEN_SECRET" >> "$CONFIG_FILE"
echo -ne "\n Setup completed!\n"
break
else
print " FAILED\n"
ERROR_STATUS=1
fi
done;
remove_temp_files
exit $ERROR_STATUS
fi
################
#### START ####
################
COMMAND=${@:$OPTIND:1}
ARG1=${@:$OPTIND+1:1}
ARG2=${@:$OPTIND+2:1}
let argnum=$#-$OPTIND
#CHECKING PARAMS VALUES
case $COMMAND in
upload)
if [[ $argnum -lt 2 ]]; then
usage
fi
FILE_DST=${@:$#:1}
for (( i=$OPTIND+1; i<$#; i++ )); do
FILE_SRC=${@:$i:1}
db_upload "$FILE_SRC" "/$FILE_DST"
done
;;
download)
if [[ $argnum -lt 1 ]]; then
usage
fi
FILE_SRC=$ARG1
FILE_DST=$ARG2
db_download "/$FILE_SRC" "$FILE_DST"
;;
share)
if [[ $argnum -lt 1 ]]; then
usage
fi
FILE_DST=$ARG1
db_share "/$FILE_DST"
;;
info)
db_account_info
;;
delete|remove)
if [[ $argnum -lt 1 ]]; then
usage
fi
FILE_DST=$ARG1
db_delete "/$FILE_DST"
;;
move|rename)
if [[ $argnum -lt 2 ]]; then
usage
fi
FILE_SRC=$ARG1
FILE_DST=$ARG2
db_move "/$FILE_SRC" "/$FILE_DST"
;;
copy)
if [[ $argnum -lt 2 ]]; then
usage
fi
FILE_SRC=$ARG1
FILE_DST=$ARG2
db_copy "/$FILE_SRC" "/$FILE_DST"
;;
mkdir)
if [[ $argnum -lt 1 ]]; then
usage
fi
DIR_DST=$ARG1
db_mkdir "/$DIR_DST"
;;
list)
DIR_DST=$ARG1
#Checking DIR_DST
if [[ $DIR_DST == "" ]]; then
DIR_DST="/"
fi
db_list "/$DIR_DST"
;;
unlink)
db_unlink
;;
*)
if [[ $COMMAND != "" ]]; then
print "Error: Unknown command: $COMMAND\n\n"
ERROR_STATUS=1
fi
usage
;;
esac
remove_temp_files
exit $ERROR_STATUS
For the first time, this script will give you instructions on where to get the Dropbox API key.
Because only the API key is configured to authorize the application of the script into your Dropbox directory