Last active
August 19, 2021 11:46
-
-
Save meoow/e73500c1b0cd4f8541a1 to your computer and use it in GitHub Desktop.
百度云命令行(bash)上传下载脚本
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/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) | |
} | |
} | |
' | |
} | |
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