Skip to content

Instantly share code, notes, and snippets.

@hankcs
Forked from meoow/bdcurl.sh
Created October 18, 2015 03:59
Show Gist options
  • Save hankcs/7490831a5f2476d40289 to your computer and use it in GitHub Desktop.
Save hankcs/7490831a5f2476d40289 to your computer and use it in GitHub Desktop.
百度云命令行(bash)上传下载脚本
#!/bin/bash
# Baidu Yun Command Line Interface
# Depends: bash, curl, grep, awk, sed, od
# (They are basicly builtin tools of any *nix system.)
# Additionally, fastupload depends: head, wc, md5sum or md5, cksum
# (Which are also builtin tools)
#### Variables ####
# This three to be changed to your own code #
# but using bdcurl.sh auth, the token could be updated by the script itself,
# if you have write permission for the resided directory.
TOKEN=00.00000000000000000000000000000000.0000000.0000000000.0000000000-0000000
# baidu has prohibited registering new client id
# the client_id is borrowed from bypy (Another great baidu yun cli tool written in python)
CLIENT_ID=q8WE4EpCsau1oS0MplgMKNBn
# you should at least login pan.baidu.com from browser once,
# then you can obtain the BDUSS code in the Cookie.
BDUSS='XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX;'
########################################
# Note that the root of baidu yun server is located at per app specified path($pathprefix),
# not the real root.
pathprefix='/apps/bypy/'
ACCEPT='text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8'
ACCPET_LANGUAGE='zh-cn,zh;q=0.8,en-us;q=0.5,en;q=0.3'
ACCPET_ENCODING='identity'
CACHE_CONTROL='no-cache'
CONNECTION='keep-alive'
DNT=1
HOST='pcs.baidu.com'
ORIGIN='http://pan.baidu.com'
PRAGMA='no-cache'
REFERER='http://pan.baidu.com/disk/home'
UA='Mozilla/5.0 (X11; Linux; rv:5.0) Gecko/5.0 Firefox/5.0'
CURL_DEFAULT_ARGS=(
-H "Accept: $ACCEPT"
-H "Accept-Language: $ACCPET_LANGUAGE"
-H "Cache-Control: $CACHE_CONTROL"
-H "Connection: $CONNECTION"
-H "DNT: $DNT"
-H "Host: $HOST"
-H "Origin: $ORIGIN"
-H "Pragma: $PRAGMA"
-H "Referer: $REFERER"
-H "Accept-Encoding: $ACCPET_ENCODING"
-A "$UA"
)
####################
#### Defining functions ####
# encoding character to %xx format
urlencode() {
local length="${#1}"
local c
for (( i = 0; i < length; i++ )); do
c="${1:i:1}"
case $c in
[a-zA-Z0-9.~_-]) printf "%s" "$c" ;;
*) printf "%s" "$c" | od -t x1 |
awk '{for(i=2;i<=NF;i++)print $i}' |
while read x;do printf "%%%s" "$x";done
esac
done
}
# for *basic* regexp syntax surrounded by double quotes
regexescape() {
local len="${#1}"
local c
for(( i=0;i<len;i++ ));do
c="${1:i:1}"
case "$c" in
[*\\/^$]|']'|'['|'-')
printf "\\\\%s" "$c"
;;
*)
printf "%s" "$c"
esac
done
}
# baidu yun authorize
auth() {
local code token
printf '\e[1mGetting auth code from:\e[0m\n'
echo "http://openapi.baidu.com/oauth/2.0/authorize?response_type=code&client_id=$CLIENT_ID&redirect_uri=oob&scope=basic%20netdisk&"
code=$(curl -Ls "http://openapi.baidu.com/oauth/2.0/authorize?response_type=code&client_id=$CLIENT_ID&redirect_uri=oob&scope=basic%20netdisk&" -H "Cookie: BDUSS=$BDUSS"|grep -o 'readonly value="[^"]*"'|grep -o '[[:xdigit:]]\{32\}')
if [[ -z "$code" ]];then
echo Failed, exit...
exit 1
fi
printf 'Auth code is \e[1;31m%s\e[0m\n' "$code"
echo
printf '\e[1mGetting token from:\e[0m\n'
echo "https://bypy-tianze.rhcloud.com/auth?code=$code&redirect_uri=oob&"
token=$(curl -3 -Ls "https://bypy-tianze.rhcloud.com/auth?code=$code&redirect_uri=oob&" \
-A 'Mozilla/5.0 (X11; Linux x86_64; rv:26.0) Gecko/20100101 Firefox/26.0' \
-H 'Host: bypy-tianze.rhcloud.com'|
grep -o '"[^"]\{1,\}":"[^"]\{1,\}"'|sed -n '/access_token/s/^.*:"\([[:xdigit:].-]\{1,\}\)"$/\1/p')
if [[ -n "$token" ]];then
printf 'Token is \e[1;31m%s\e[0m\n' "$token"
echo
printf '\e[1mUpdating token in this script...\e[0m\n'
local scriptdir=$(dirname "$0")
if [[ -w "$scriptdir" ]] && [[ -x "$scriptdir" ]];then
sed -i '~' -e "s/^TOKEN=.*$/TOKEN=$token/" "$0"
rm "$0~"
printf '\e[1mToken updated\e[0m\n'
else
echo You don\'t have write permission for $0,
echo you need to add the token string into this script manually.
exit 1
fi
fi
}
# print help
usage() {
cat <<_EOF_
$0 <command> [arguments...]
Command:
auth
upload <FILE> [PATH] [overwrite|newcopy]
fastupload <FILE> [PATH] [overwrite|newcopy]
download <PATH> [SAVEDIR] [SAVENAME]
downdir <DIR> [SAVEDIR]
list [PATH]
mkdir <PATH>
meta <PATH>
move <FROM> <TO>
copy <FROM> <TO>
delete <PATH>
search <PATH> <WORD>
add <URI> [PATH]
query <TASKID>
tasks
cancel <TASKID>
trash
retore <FILEID>
_EOF_
}
# JSON pretty printer
tokenize () {
local GREP
local ESCAPE
local CHAR
GREP='egrep -ao'
ESCAPE='(\\[^u[:cntrl:]]|\\u[0-9a-fA-F]{4})'
CHAR='[^[:cntrl:]"\\]'
local STRING="\"$CHAR*($ESCAPE$CHAR*)*\""
local NUMBER='-?(0|[1-9][0-9]*)([.][0-9]*)?([eE][+-]?[0-9]*)?'
local KEYWORD='null|false|true'
local SPACE='[[:space:]]+'
$GREP "$STRING|$NUMBER|$KEYWORD|$SPACE|." | egrep -v "^$SPACE$"
}
printw() {
local n="$1"
if [[ "$n" =~ [1-9][0-9]* ]];then
:
else
return 0
fi
for((i=0;i<n;i++));do
printf " "
done
}
pprint() {
local indent=0
local value=0
while read x; do
case "$x" in
'{'|'[')
if ((value));then
printf " "
value=0
else
printw $indent
fi
((indent++))
printf "%s\n" "$x"
;;
'}'|']')
value=0
((indent>0 && indent--))
echo
printw $indent
printf "%s" "$x"
;;
',')
value=0
echo
;;
':')
value=1
printf "%s" "$x"
;;
*)
if ((value));then
value=0
printf " "
else
printw $indent
fi
printf "%s" "$x"
;;
esac
done
}
# compact json output (parse output from pprint only)
compact() {
# arguments: -f -t -b -m -s
# -f no fs_id
# -t no ctime and mtime
# -b no brackets
# -m no md5
# -s no size
#default is to remove double quotes
local sedcmd='s/"\([^"]*\)"/\1/g;'
while getopts :ftbms arg;do
case "$arg" in
f)
sedcmd="$sedcmd"'/^ *fs_id/d;'
;;
t)
sedcmd="$sedcmd"'/^ *ctime/d;/^ *mtime/d;'
;;
m)
sedcmd="$sedcmd"'/^ *md5:/d;'
;;
s)
sedcmd="$sedcmd"'/^ *size:/d;'
;;
b) sedcmd="$sedcmd"'/^ *{/d;s/^ *}$//;/^ *\[$/d;/^ *\]/d;s/: \[$/:/;'
;;
esac
done
sed "$sedcmd"
}
autounit() {
awk -v G=$((1024**3)) -v M=$((1024**2)) -v K=1024 '
{
if($0~/^ *"?size"?: [[:digit:]]{1,}/){
if($2>=G){
size=sprintf("%0.1fG",$2/G)
} else if($2>=M){
size=sprintf("%0.1fM",$2/M)
} else if($2>=K){
size=sprintf("%0.1fK",$2/K)
} else {
size=$2
}
sub($2,size)
}
print
}
'
}
crc32() {
cksum -o3 < "$1" |
while read x y;do
echo $x
break
done
}
if type -t md5sum >/dev/null ;then
MD5='md5sum -b'
else
MD5='md5'
fi
md5() {
MD5 < "$1" |
while read x y;do
echo "$x"
break
done
}
md5_256k() {
head -c262144 "$1" | MD5 |
while read x y;do
echo "$x"
break
done
}
size() {
wc -c "$1"|
while read x y;do
echo "$x"
break
done
}
########################################
#### Parse command line arguments ####
case "$1" in
auth) auth
exit 0
;;
u|upload)
method=upload
shift
if [[ -z "$1" ]];then
echo "$0 upload <FILE> [PATH] [overwrite|newcopy]" >&2
exit 1
fi
filepath="$1"
filename="$(basename "$filepath")"
shift
path="${1:-/}/$filename"
shift
ondup="${1:-overwrite}"
;;
f|fastupload)
method=rapidupload
shift
if [[ -z "$1" ]];then
echo "$0 upload <FILE> [PATH] [overwrite|newcopy]" >&2
exit 1
fi
filepath="$1"
filename="$(basename "$filepath")"
shift
path="${1:-/}/$filename"
shift
ondup="${1:-overwrite}"
;;
d|download)
method=download
shift
if [[ -z "$1" ]];then
echo "$0 download <PATH> [SAVEDIR] [SAVENAME]" >&2
exit 1
fi
path="$1"
shift
savedir="${1:-.}"
shift
savename="${1:-$(basename "$path")}"
savefile="$savedir/$savename"
;;
mkdir)
req=POST
method=mkdir
shift
if [[ -z "$1" ]];then
echo "$0 mkdir <PATH>" >&2
exit 1
fi
path="$1"
;;
meta)
req=GET
method=meta
shift
if [[ -z "$1" ]];then
echo "$0 meta <PATH>" >&2
exit 1
fi
path="$1"
;;
l|list)
method=list
shift
path="${1:-/}"
;;
m|move)
method=move
shift
from="$1"
shift
to="$1"
if [[ -z "$from" || -z "$to" ]];then
echo "$0 move <FROM> <TO>" >&2
exit 1
fi
;;
c|copy)
method=copy
shift
from="$1"
shift
to="$1"
if [[ -z "$from" || -z "$to" ]];then
echo "$0 copy <FROM> <TO>" >&2
exit 1
fi
;;
s|search)
method=search
shift
path="$1"
shift
wd="$1"
if [[ -z "$path" || -z "$wd" ]];then
echo "$0 search <PATH> <WORD>" >&2
exit 1
fi
;;
del|delete)
method=delete
if [[ -z "$1" ]];then
echo "$0 delete <PATH>" >&2
exit 1
fi
shift
path="$1"
;;
add)
method=add_task
shift
if [[ -z "$1" ]];then
echo "$0 add <LINK>" >&2
exit 1
fi
link="$1"
shift
path="$1"
;;
query)
method=query_task
shift
if [[ -z "$1" ]];then
echo "$0 query <TASKID>" >&2
exit 1
fi
taskid="$1"
;;
tasks)
method=list_task
;;
cancel)
method=cancel_task
shift
if [[ -z "$1" ]];then
echo "$0 cancel <TASKID>" >&2
exit 1
fi
taskid="$1"
;;
trash)
method=listrecycle
;;
restore)
method=restore
shift
if [[ -z "$1" ]];then
echo "$0 restore <FILEID>" >&2
exit 1
fi
fsid="$1"
;;
h|help)
usage
exit 0
;;
*)
usage
exit 0
;;
esac
path="$pathprefix""$path"
from="$pathprefix""$from"
to="$pathprefix""$to"
#### determining request type ####
case $method in
info|download|meta|list|search|generate|diff|streaming|listrecycle)
req=GET
;;
upload|delete|createsuperfile|move|copy|rapidupload|add_task|list_task|query_task|cancel_task|restore|mkdir)
req=POST
;;
esac
##################################
#### determining URI #############
case $method in
upload) uriprefix='https://c.pcs.baidu.com/rest/2.0/pcs/file'
;;
download) uriprefix='https://d.pcs.baidu.com/rest/2.0/pcs/file'
;;
add_task|list_task|query_task|cancel_task)
uriprefix='https://pcs.baidu.com/rest/2.0/pcs/services/cloud_dl'
;;
*) uriprefix='https://pcs.baidu.com/rest/2.0/pcs/file'
;;
esac
##################################
#### Building URI depends on specific method ####
uriprefix="$uriprefix?access_token=$TOKEN&method=$method"
case $method in
upload)
uri="$uriprefix&path=$(urlencode "$path")&ondup=$ondup"
;;
download|mkdir|meta|delete)
uri="$uriprefix&path=$(urlencode "$path")"
;;
list)
by=name #time name size
order=asc #asc desc
uri="$uriprefix&path=$(urlencode "$path")&by=$by&order=$order"
;;
move|copy)
uri="$uriprefix"
;;
search)
re=1
uri="$uriprefix&path=$(urlencode "$path")&wd=$(urlencode "$wd")&re=$re"
;;
rapidupload)
filelength=$(size "$filepath")
filemd5=$(md5 "$filepath")
fileslicemd5=$(md5_256k "$filepath")
filecrc32=$(crc32 "$filepath")
uri="$uriprefix&path=$(urlencode "$path")&content-length=$filelength&content-md5=$filemd5&slice-md5=$fileslicemd5&content-crc32=$filecrc32&ondup=$ondup"
;;
add_task)
uri="$uriprefix&save_path=$(urlencode "$path")&source_url=$(urlencode "$link")"
;;
query_task)
optype=1
uri="$uriprefix&task_ids=$taskid&op_type=$optype"
;;
list_task)
start=0
limit=20
asc=0 #0 1
task_info=1 #1 0
uri="$uriprefix&start=$start&limit=$limit&asc=$asc&need_task_info=$task_info"
;;
cancel_task)
uri="$uriprefix&task_id=$taskid"
;;
listrecycle)
uri="$uriprefix&start=0"
;;
restore)
uri="$uriprefix&fs_id=$fsid"
;;
esac
######################################
## Building arguments for CURL ##
curlopts=(
-X$req
"${CURL_DEFAULT_ARGS[@]}"
)
case $method in
upload)
curlopts=("${curlopts[@]}" -F file=@"$filepath" "$uri")
;;
download)
curlopts=("${curlopts[@]}" -L -o "$savefile" "$uri")
;;
delete|add_task|list_task|query_task|cancel_task|restore|mkdir|rapidupload)
curlopts=(
"${curlopts[@]}"
-H "Content-Length: 0"
-Ls "$uri"
)
;;
move|copy)
curlopts=(
"${curlopts[@]}"
#-H "Content-Type: application/json"
-H "Content-Length: 0"
#--data param="{\"list\":[{\"from\":\"$from\",\"to\":\"$to\"}]}"
-Ls "$uri&from=$(urlencode "$from")&to=$(urlencode "$to")"
)
;;
*)
curlopts=("${curlopts[@]}" -Ls "$uri")
;;
esac
#################################
### Start the operation ###
# echo "${curlopts[@]}"; exit
case $method in
download)
curl "${curlopts[@]}"
;;
*)
curl "${curlopts[@]}"|
tokenize|pprint|
sed '/^ *"path": /s/^\( *"path": "\)'"$(regexescape "$pathprefix")"'\(.*"\)$/\1\2/'|
compact -ftbm | autounit
;;
esac
###########################
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment