refractor command
This commit is contained in:
parent
70776dea87
commit
f3b12f34bf
|
@ -0,0 +1,139 @@
|
|||
package cmder
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/tickstep/cloudpan189-api/cloudpan"
|
||||
"github.com/tickstep/cloudpan189-api/cloudpan/apierror"
|
||||
"github.com/tickstep/cloudpan189-go/cmder/cmdliner"
|
||||
"github.com/tickstep/cloudpan189-go/internal/config"
|
||||
"github.com/tickstep/library-go/logger"
|
||||
"github.com/urfave/cli"
|
||||
"sync"
|
||||
)
|
||||
|
||||
var (
|
||||
appInstance *cli.App
|
||||
|
||||
saveConfigMutex *sync.Mutex = new(sync.Mutex)
|
||||
|
||||
ReloadConfigFunc = func(c *cli.Context) error {
|
||||
err := config.Config.Reload()
|
||||
if err != nil {
|
||||
fmt.Printf("重载配置错误: %s\n", err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
SaveConfigFunc = func(c *cli.Context) error {
|
||||
saveConfigMutex.Lock()
|
||||
defer saveConfigMutex.Unlock()
|
||||
err := config.Config.Save()
|
||||
if err != nil {
|
||||
fmt.Printf("保存配置错误: %s\n", err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
)
|
||||
|
||||
func SetApp(app *cli.App) {
|
||||
appInstance = app
|
||||
}
|
||||
|
||||
func App() *cli.App {
|
||||
return appInstance
|
||||
}
|
||||
|
||||
func DoLoginHelper(username, password string) (usernameStr, passwordStr string, webToken cloudpan.WebLoginToken, appToken cloudpan.AppLoginToken, error error) {
|
||||
line := cmdliner.NewLiner()
|
||||
defer line.Close()
|
||||
|
||||
if username == "" {
|
||||
username, error = line.State.Prompt("请输入用户名(手机号/邮箱/别名), 回车键提交 > ")
|
||||
if error != nil {
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
if password == "" {
|
||||
// liner 的 PasswordPrompt 不安全, 拆行之后密码就会显示出来了
|
||||
fmt.Printf("请输入密码(输入的密码无回显, 确认输入完成, 回车提交即可) > ")
|
||||
password, error = line.State.PasswordPrompt("")
|
||||
if error != nil {
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
// app login
|
||||
atoken, apperr := cloudpan.AppLogin(username, password)
|
||||
if apperr != nil {
|
||||
fmt.Println("APP登录失败:", apperr)
|
||||
return "", "", webToken, appToken, fmt.Errorf("登录失败")
|
||||
}
|
||||
|
||||
// web cookie
|
||||
wtoken := &cloudpan.WebLoginToken{}
|
||||
cookieLoginUser := cloudpan.RefreshCookieToken(atoken.SessionKey)
|
||||
if cookieLoginUser != "" {
|
||||
logger.Verboseln("get COOKIE_LOGIN_USER by session key")
|
||||
wtoken.CookieLoginUser = cookieLoginUser
|
||||
} else {
|
||||
// try login directly
|
||||
wtoken, apperr = cloudpan.Login(username, password)
|
||||
if apperr != nil {
|
||||
if apperr.Code == apierror.ApiCodeNeedCaptchaCode {
|
||||
for i := 0; i < 10; i++ {
|
||||
// 需要认证码
|
||||
savePath, apiErr := cloudpan.GetCaptchaImage()
|
||||
if apiErr != nil {
|
||||
fmt.Errorf("获取认证码错误")
|
||||
return "", "", webToken, appToken, apiErr
|
||||
}
|
||||
fmt.Printf("打开以下路径, 以查看验证码\n%s\n\n", savePath)
|
||||
vcode, err := line.State.Prompt("请输入验证码 > ")
|
||||
if err != nil {
|
||||
return "", "", webToken, appToken, err
|
||||
}
|
||||
wtoken, apiErr = cloudpan.LoginWithCaptcha(username, password, vcode)
|
||||
if apiErr != nil {
|
||||
return "", "", webToken, appToken, apiErr
|
||||
} else {
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
} else {
|
||||
return "", "", webToken, appToken, fmt.Errorf("登录失败")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
webToken = *wtoken
|
||||
appToken = *atoken
|
||||
usernameStr = username
|
||||
passwordStr = password
|
||||
return
|
||||
}
|
||||
|
||||
func TryLogin() *config.PanUser {
|
||||
// can do automatically login?
|
||||
for _, u := range config.Config.UserList {
|
||||
if u.UID == config.Config.ActiveUID {
|
||||
// login
|
||||
_, _, webToken, appToken, err := DoLoginHelper(config.DecryptString(u.LoginUserName), config.DecryptString(u.LoginUserPassword))
|
||||
if err != nil {
|
||||
logger.Verboseln("automatically login error")
|
||||
break
|
||||
}
|
||||
// success
|
||||
u.WebToken = webToken
|
||||
u.AppToken = appToken
|
||||
|
||||
// save
|
||||
SaveConfigFunc(nil)
|
||||
// reload
|
||||
ReloadConfigFunc(nil)
|
||||
return config.Config.ActiveUser()
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
|
@ -13,8 +13,11 @@
|
|||
// limitations under the License.
|
||||
package command
|
||||
|
||||
import "C"
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/tickstep/cloudpan189-go/cmder"
|
||||
"github.com/tickstep/cloudpan189-go/internal/config"
|
||||
"os"
|
||||
"path"
|
||||
"path/filepath"
|
||||
|
@ -25,16 +28,9 @@ import (
|
|||
"github.com/tickstep/cloudpan189-api/cloudpan"
|
||||
"github.com/tickstep/cloudpan189-go/internal/functions/panupload"
|
||||
"github.com/urfave/cli"
|
||||
"github.com/tickstep/cloudpan189-go/internal/config"
|
||||
)
|
||||
|
||||
type backupFunc struct {
|
||||
User *config.PanUser
|
||||
Client *cloudpan.PanClient
|
||||
}
|
||||
|
||||
func CmdBackup() cli.Command {
|
||||
cmd := &backupFunc{}
|
||||
return cli.Command{
|
||||
Name: "backup",
|
||||
Description: `备份指定 <文件/目录> 到云盘 <目标目录> 中
|
||||
|
@ -51,8 +47,8 @@ func CmdBackup() cli.Command {
|
|||
Usage: "备份文件或目录",
|
||||
UsageText: "backup <文件/目录路径1> <文件/目录2> <文件/目录3> ... <目标目录>",
|
||||
Category: "天翼云盘",
|
||||
Before: cmd.Before,
|
||||
Action: cmd.Backup,
|
||||
Before: cmder.ReloadConfigFunc,
|
||||
Action: Backup,
|
||||
Flags: append(UploadFlags, cli.BoolFlag{
|
||||
Name: "delete",
|
||||
Usage: "通过本地数据库记录同步删除网盘文件",
|
||||
|
@ -63,25 +59,13 @@ func CmdBackup() cli.Command {
|
|||
}
|
||||
}
|
||||
|
||||
func (c *backupFunc) Before(cli *cli.Context) error {
|
||||
if cli.NArg() < 2 {
|
||||
return ErrBadArgs
|
||||
}
|
||||
User := config.Config.ActiveUser()
|
||||
if User == nil {
|
||||
return ErrNotLogined
|
||||
}
|
||||
c.User = User
|
||||
c.Client = User.PanClient()
|
||||
return nil
|
||||
}
|
||||
|
||||
func OpenSyncDb(path string) (panupload.SyncDb, error) {
|
||||
return panupload.OpenSyncDb(path, "ecloud")
|
||||
}
|
||||
|
||||
// 删除那些本地不存在而网盘存在的网盘文件 默认使用本地数据库判断,如果 flagSync 为 true 则遍历网盘文件列表进行判断(速度较慢)。
|
||||
func (c *backupFunc) DelRemoteFileFromDB(familyId int64, localDir string, savePath string, flagSync bool) {
|
||||
func DelRemoteFileFromDB(familyId int64, localDir string, savePath string, flagSync bool) {
|
||||
activeUser := config.Config.ActiveUser()
|
||||
var db panupload.SyncDb
|
||||
var err error
|
||||
dbpath := filepath.Join(localDir, ".ecloud")
|
||||
|
@ -120,7 +104,7 @@ func (c *backupFunc) DelRemoteFileFromDB(familyId int64, localDir string, savePa
|
|||
}
|
||||
|
||||
if ent.FileID == "" || ent.ParentId == "" {
|
||||
efi, err := c.Client.AppGetBasicFileInfo(&cloudpan.AppGetFileInfoParam{
|
||||
efi, err := activeUser.PanClient().AppGetBasicFileInfo(&cloudpan.AppGetFileInfoParam{
|
||||
FileId: ent.FileID,
|
||||
FilePath: ent.Path,
|
||||
})
|
||||
|
@ -158,9 +142,9 @@ func (c *backupFunc) DelRemoteFileFromDB(familyId int64, localDir string, savePa
|
|||
}
|
||||
|
||||
if familyId > 0 {
|
||||
taskId, err = c.Client.AppCreateBatchTask(familyId, delParam)
|
||||
taskId, err = activeUser.PanClient().AppCreateBatchTask(familyId, delParam)
|
||||
} else {
|
||||
taskId, err = c.Client.CreateBatchTask(delParam)
|
||||
taskId, err = activeUser.PanClient().CreateBatchTask(delParam)
|
||||
}
|
||||
if err != nil || taskId == "" {
|
||||
fmt.Println("删除网盘文件或目录失败", ent.Path, err)
|
||||
|
@ -182,7 +166,7 @@ func (c *backupFunc) DelRemoteFileFromDB(familyId int64, localDir string, savePa
|
|||
parent := db.Get(savePath)
|
||||
|
||||
if parent.FileID == "" {
|
||||
efi, err := c.Client.AppGetBasicFileInfo(&cloudpan.AppGetFileInfoParam{
|
||||
efi, err := activeUser.PanClient().AppGetBasicFileInfo(&cloudpan.AppGetFileInfoParam{
|
||||
FilePath: savePath,
|
||||
})
|
||||
if err != nil {
|
||||
|
@ -197,7 +181,7 @@ func (c *backupFunc) DelRemoteFileFromDB(familyId int64, localDir string, savePa
|
|||
param := cloudpan.NewAppFileListParam()
|
||||
param.FileId = parentID
|
||||
param.FamilyId = familyId
|
||||
fileResult, err := c.Client.AppGetAllFileList(param)
|
||||
fileResult, err := activeUser.PanClient().AppGetAllFileList(param)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
@ -236,7 +220,7 @@ func (c *backupFunc) DelRemoteFileFromDB(familyId int64, localDir string, savePa
|
|||
syncFunc(savePath, parent.FileID)
|
||||
}
|
||||
|
||||
func (c *backupFunc) checkPath(localdir string) (string, error) {
|
||||
func checkPath(localdir string) (string, error) {
|
||||
fullPath, err := filepath.Abs(localdir)
|
||||
if err != nil {
|
||||
fullPath = localdir
|
||||
|
@ -266,7 +250,7 @@ func (c *backupFunc) checkPath(localdir string) (string, error) {
|
|||
return fullPath, nil
|
||||
}
|
||||
|
||||
func (c *backupFunc) Backup(cli *cli.Context) error {
|
||||
func Backup(cli *cli.Context) error {
|
||||
subArgs := cli.Args()
|
||||
localpaths := make([]string, 0)
|
||||
flagSync := cli.Bool("sync")
|
||||
|
@ -291,11 +275,11 @@ func (c *backupFunc) Backup(cli *cli.Context) error {
|
|||
for _, p := range subArgs[:localCount] {
|
||||
go func(p string) {
|
||||
defer wg.Done()
|
||||
fullPath, err := c.checkPath(p)
|
||||
fullPath, err := checkPath(p)
|
||||
switch err {
|
||||
case nil:
|
||||
if flagSync || flagDelete {
|
||||
c.DelRemoteFileFromDB(opt.FamilyId, fullPath, savePath, flagSync)
|
||||
DelRemoteFileFromDB(opt.FamilyId, fullPath, savePath, flagSync)
|
||||
}
|
||||
case os.ErrInvalid:
|
||||
default:
|
||||
|
|
|
@ -15,9 +15,76 @@ package command
|
|||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/tickstep/cloudpan189-go/cmder"
|
||||
"github.com/tickstep/cloudpan189-go/internal/config"
|
||||
"github.com/urfave/cli"
|
||||
)
|
||||
|
||||
func CmdCd() cli.Command {
|
||||
return cli.Command{
|
||||
Name: "cd",
|
||||
Category: "天翼云盘",
|
||||
Usage: "切换工作目录",
|
||||
Description: `
|
||||
cloudpan189-go cd <目录, 绝对路径或相对路径>
|
||||
|
||||
示例:
|
||||
|
||||
切换 /我的资源 工作目录:
|
||||
cloudpan189-go cd /我的资源
|
||||
|
||||
切换上级目录:
|
||||
cloudpan189-go cd ..
|
||||
|
||||
切换根目录:
|
||||
cloudpan189-go cd /
|
||||
`,
|
||||
Before: cmder.ReloadConfigFunc,
|
||||
After: cmder.SaveConfigFunc,
|
||||
Action: func(c *cli.Context) error {
|
||||
if c.NArg() == 0 {
|
||||
cli.ShowCommandHelp(c, c.Command.Name)
|
||||
return nil
|
||||
}
|
||||
if config.Config.ActiveUser() == nil {
|
||||
fmt.Println("未登录账号")
|
||||
return nil
|
||||
}
|
||||
RunChangeDirectory(parseFamilyId(c), c.Args().Get(0))
|
||||
return nil
|
||||
},
|
||||
Flags: []cli.Flag{
|
||||
cli.StringFlag{
|
||||
Name: "familyId",
|
||||
Usage: "家庭云ID",
|
||||
Value: "",
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func CmdPwd() cli.Command {
|
||||
return cli.Command{
|
||||
Name: "pwd",
|
||||
Usage: "输出工作目录",
|
||||
UsageText: cmder.App().Name + " pwd",
|
||||
Category: "天翼云盘",
|
||||
Before: cmder.ReloadConfigFunc,
|
||||
Action: func(c *cli.Context) error {
|
||||
if config.Config.ActiveUser() == nil {
|
||||
fmt.Println("未登录账号")
|
||||
return nil
|
||||
}
|
||||
if IsFamilyCloud(config.Config.ActiveUser().ActiveFamilyId) {
|
||||
fmt.Println(config.Config.ActiveUser().FamilyWorkdir)
|
||||
} else {
|
||||
fmt.Println(config.Config.ActiveUser().Workdir)
|
||||
}
|
||||
return nil
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func RunChangeDirectory(familyId int64, targetPath string) {
|
||||
user := config.Config.ActiveUser()
|
||||
targetPath = user.PathJoin(familyId, targetPath)
|
||||
|
|
|
@ -15,6 +15,11 @@ package command
|
|||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"github.com/tickstep/cloudpan189-go/cmder"
|
||||
"github.com/tickstep/cloudpan189-go/cmder/cmdutil"
|
||||
"github.com/tickstep/cloudpan189-go/library/crypto"
|
||||
"github.com/tickstep/library-go/getip"
|
||||
"strconv"
|
||||
|
||||
"github.com/urfave/cli"
|
||||
|
@ -23,6 +28,22 @@ import (
|
|||
"github.com/tickstep/cloudpan189-go/internal/config"
|
||||
)
|
||||
|
||||
const (
|
||||
cryptoDescription = `
|
||||
可用的方法 <method>:
|
||||
aes-128-ctr, aes-192-ctr, aes-256-ctr,
|
||||
aes-128-cfb, aes-192-cfb, aes-256-cfb,
|
||||
aes-128-ofb, aes-192-ofb, aes-256-ofb.
|
||||
|
||||
密钥 <key>:
|
||||
aes-128 对应key长度为16, aes-192 对应key长度为24, aes-256 对应key长度为32,
|
||||
如果key长度不符合, 则自动修剪key, 舍弃超出长度的部分, 长度不足的部分用'\0'填充.
|
||||
|
||||
GZIP <disable-gzip>:
|
||||
在文件加密之前, 启用GZIP压缩文件; 文件解密之后启用GZIP解压缩文件, 默认启用,
|
||||
如果不启用, 则无法检测文件是否解密成功, 解密文件时会保留源文件, 避免解密失败造成文件数据丢失.`
|
||||
)
|
||||
|
||||
var ErrBadArgs = errors.New("参数错误")
|
||||
var ErrNotLogined = errors.New("未登录账号")
|
||||
|
||||
|
@ -46,3 +67,246 @@ func parseFamilyId(c *cli.Context) int64 {
|
|||
}
|
||||
return familyId
|
||||
}
|
||||
|
||||
|
||||
|
||||
func CmdConfig() cli.Command {
|
||||
return cli.Command{
|
||||
Name: "config",
|
||||
Usage: "显示和修改程序配置项",
|
||||
Description: "显示和修改程序配置项",
|
||||
Category: "配置",
|
||||
Before: cmder.ReloadConfigFunc,
|
||||
After: cmder.SaveConfigFunc,
|
||||
Action: func(c *cli.Context) error {
|
||||
fmt.Printf("----\n运行 %s config set 可进行设置配置\n\n当前配置:\n", cmder.App().Name)
|
||||
config.Config.PrintTable()
|
||||
return nil
|
||||
},
|
||||
Subcommands: []cli.Command{
|
||||
{
|
||||
Name: "set",
|
||||
Usage: "修改程序配置项",
|
||||
UsageText: cmder.App().Name + " config set [arguments...]",
|
||||
Description: `
|
||||
注意:
|
||||
可通过设置环境变量 CLOUD189_CONFIG_DIR, 指定配置文件存放的目录.
|
||||
|
||||
cache_size 的值支持可选设置单位, 单位不区分大小写, b 和 B 均表示字节的意思, 如 64KB, 1MB, 32kb, 65536b, 65536
|
||||
max_download_rate, max_upload_rate 的值支持可选设置单位, 单位为每秒的传输速率, 后缀'/s' 可省略, 如 2MB/s, 2MB, 2m, 2mb 均为一个意思
|
||||
|
||||
例子:
|
||||
cloudpan189-go config set -cache_size 64KB
|
||||
cloudpan189-go config set -cache_size 16384 -max_download_parallel 200 -savedir D:/download`,
|
||||
Action: func(c *cli.Context) error {
|
||||
if c.NumFlags() <= 0 || c.NArg() > 0 {
|
||||
cli.ShowCommandHelp(c, c.Command.Name)
|
||||
return nil
|
||||
}
|
||||
if c.IsSet("cache_size") {
|
||||
err := config.Config.SetCacheSizeByStr(c.String("cache_size"))
|
||||
if err != nil {
|
||||
fmt.Printf("设置 cache_size 错误: %s\n", err)
|
||||
return nil
|
||||
}
|
||||
}
|
||||
if c.IsSet("max_download_parallel") {
|
||||
config.Config.MaxDownloadParallel = c.Int("max_download_parallel")
|
||||
}
|
||||
if c.IsSet("max_upload_parallel") {
|
||||
config.Config.MaxUploadParallel = c.Int("max_upload_parallel")
|
||||
}
|
||||
if c.IsSet("max_download_load") {
|
||||
config.Config.MaxDownloadLoad = c.Int("max_download_load")
|
||||
}
|
||||
if c.IsSet("max_download_rate") {
|
||||
err := config.Config.SetMaxDownloadRateByStr(c.String("max_download_rate"))
|
||||
if err != nil {
|
||||
fmt.Printf("设置 max_download_rate 错误: %s\n", err)
|
||||
return nil
|
||||
}
|
||||
}
|
||||
if c.IsSet("max_upload_rate") {
|
||||
err := config.Config.SetMaxUploadRateByStr(c.String("max_upload_rate"))
|
||||
if err != nil {
|
||||
fmt.Printf("设置 max_upload_rate 错误: %s\n", err)
|
||||
return nil
|
||||
}
|
||||
}
|
||||
if c.IsSet("savedir") {
|
||||
config.Config.SaveDir = c.String("savedir")
|
||||
}
|
||||
if c.IsSet("proxy") {
|
||||
config.Config.SetProxy(c.String("proxy"))
|
||||
}
|
||||
if c.IsSet("local_addrs") {
|
||||
config.Config.SetLocalAddrs(c.String("local_addrs"))
|
||||
}
|
||||
|
||||
err := config.Config.Save()
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
return err
|
||||
}
|
||||
|
||||
config.Config.PrintTable()
|
||||
fmt.Printf("\n保存配置成功!\n\n")
|
||||
|
||||
return nil
|
||||
},
|
||||
Flags: []cli.Flag{
|
||||
cli.StringFlag{
|
||||
Name: "cache_size",
|
||||
Usage: "下载缓存",
|
||||
},
|
||||
cli.IntFlag{
|
||||
Name: "max_download_parallel",
|
||||
Usage: "下载网络连接的最大并发量",
|
||||
},
|
||||
cli.IntFlag{
|
||||
Name: "max_upload_parallel",
|
||||
Usage: "上传网络连接的最大并发量",
|
||||
},
|
||||
cli.IntFlag{
|
||||
Name: "max_download_load",
|
||||
Usage: "同时进行下载文件的最大数量",
|
||||
},
|
||||
cli.StringFlag{
|
||||
Name: "max_download_rate",
|
||||
Usage: "限制最大下载速度, 0代表不限制",
|
||||
},
|
||||
cli.StringFlag{
|
||||
Name: "max_upload_rate",
|
||||
Usage: "限制最大上传速度, 0代表不限制",
|
||||
},
|
||||
cli.StringFlag{
|
||||
Name: "savedir",
|
||||
Usage: "下载文件的储存目录",
|
||||
},
|
||||
cli.StringFlag{
|
||||
Name: "proxy",
|
||||
Usage: "设置代理, 支持 http/socks5 代理",
|
||||
},
|
||||
cli.StringFlag{
|
||||
Name: "local_addrs",
|
||||
Usage: "设置本地网卡地址, 多个地址用逗号隔开",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
func CmdTool() cli.Command {
|
||||
return cli.Command{
|
||||
Name: "tool",
|
||||
Usage: "工具箱",
|
||||
Action: func(c *cli.Context) error {
|
||||
cli.ShowCommandHelp(c, c.Command.Name)
|
||||
return nil
|
||||
},
|
||||
Subcommands: []cli.Command{
|
||||
{
|
||||
Name: "getip",
|
||||
Usage: "获取IP地址",
|
||||
Action: func(c *cli.Context) error {
|
||||
fmt.Printf("内网IP地址: \n")
|
||||
for _, address := range cmdutil.ListAddresses() {
|
||||
fmt.Printf("%s\n", address)
|
||||
}
|
||||
fmt.Printf("\n")
|
||||
|
||||
ipAddr, err := getip.IPInfoFromTechainBaiduByClient(config.Config.HTTPClient(""))
|
||||
if err != nil {
|
||||
fmt.Printf("获取公网IP错误: %s\n", err)
|
||||
return nil
|
||||
}
|
||||
|
||||
fmt.Printf("公网IP地址: %s\n", ipAddr)
|
||||
return nil
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "enc",
|
||||
Usage: "加密文件",
|
||||
UsageText: cmder.App().Name + " enc -method=<method> -key=<key> [files...]",
|
||||
Description: cryptoDescription,
|
||||
Action: func(c *cli.Context) error {
|
||||
if c.NArg() <= 0 {
|
||||
cli.ShowCommandHelp(c, c.Command.Name)
|
||||
return nil
|
||||
}
|
||||
|
||||
for _, filePath := range c.Args() {
|
||||
encryptedFilePath, err := crypto.EncryptFile(c.String("method"), []byte(c.String("key")), filePath, !c.Bool("disable-gzip"))
|
||||
if err != nil {
|
||||
fmt.Printf("%s\n", err)
|
||||
continue
|
||||
}
|
||||
|
||||
fmt.Printf("加密成功, %s -> %s\n", filePath, encryptedFilePath)
|
||||
}
|
||||
|
||||
return nil
|
||||
},
|
||||
Flags: []cli.Flag{
|
||||
cli.StringFlag{
|
||||
Name: "method",
|
||||
Usage: "加密方法",
|
||||
Value: "aes-128-ctr",
|
||||
},
|
||||
cli.StringFlag{
|
||||
Name: "key",
|
||||
Usage: "加密密钥",
|
||||
Value: cmder.App().Name,
|
||||
},
|
||||
cli.BoolFlag{
|
||||
Name: "disable-gzip",
|
||||
Usage: "不启用GZIP",
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "dec",
|
||||
Usage: "解密文件",
|
||||
UsageText: cmder.App().Name + " dec -method=<method> -key=<key> [files...]",
|
||||
Description: cryptoDescription,
|
||||
Action: func(c *cli.Context) error {
|
||||
if c.NArg() <= 0 {
|
||||
cli.ShowCommandHelp(c, c.Command.Name)
|
||||
return nil
|
||||
}
|
||||
|
||||
for _, filePath := range c.Args() {
|
||||
decryptedFilePath, err := crypto.DecryptFile(c.String("method"), []byte(c.String("key")), filePath, !c.Bool("disable-gzip"))
|
||||
if err != nil {
|
||||
fmt.Printf("%s\n", err)
|
||||
continue
|
||||
}
|
||||
|
||||
fmt.Printf("解密成功, %s -> %s\n", filePath, decryptedFilePath)
|
||||
}
|
||||
|
||||
return nil
|
||||
},
|
||||
Flags: []cli.Flag{
|
||||
cli.StringFlag{
|
||||
Name: "method",
|
||||
Usage: "加密方法",
|
||||
Value: "aes-128-ctr",
|
||||
},
|
||||
cli.StringFlag{
|
||||
Name: "key",
|
||||
Usage: "加密密钥",
|
||||
Value: cmder.App().Name,
|
||||
},
|
||||
cli.BoolFlag{
|
||||
Name: "disable-gzip",
|
||||
Usage: "不启用GZIP",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
|
|
@ -16,11 +16,91 @@ package command
|
|||
import (
|
||||
"fmt"
|
||||
"github.com/tickstep/cloudpan189-api/cloudpan"
|
||||
"github.com/tickstep/cloudpan189-go/cmder"
|
||||
"github.com/tickstep/cloudpan189-go/internal/config"
|
||||
"github.com/tickstep/library-go/logger"
|
||||
"github.com/urfave/cli"
|
||||
"path"
|
||||
"time"
|
||||
)
|
||||
|
||||
func CmdCp() cli.Command {
|
||||
return cli.Command{
|
||||
Name: "cp",
|
||||
Usage: "拷贝文件/目录",
|
||||
UsageText: cmder.App().Name + ` cp <文件/目录> <目标文件/目录>
|
||||
cloudpan189-go cp <文件/目录1> <文件/目录2> <文件/目录3> ... <目标目录>`,
|
||||
Description: `
|
||||
注意: 拷贝多个文件和目录时, 请确保每一个文件和目录都存在, 否则拷贝操作会失败.
|
||||
|
||||
示例:
|
||||
|
||||
将 /我的资源/1.mp4 复制到 根目录 /
|
||||
cloudpan189-go cp /我的资源/1.mp4 /
|
||||
|
||||
将 /我的资源/1.mp4 和 /我的资源/2.mp4 复制到 根目录 /
|
||||
cloudpan189-go cp /我的资源/1.mp4 /我的资源/2.mp4 /
|
||||
`,
|
||||
Category: "天翼云盘",
|
||||
Before: cmder.ReloadConfigFunc,
|
||||
Action: func(c *cli.Context) error {
|
||||
if c.NArg() <= 1 {
|
||||
cli.ShowCommandHelp(c, c.Command.Name)
|
||||
return nil
|
||||
}
|
||||
if config.Config.ActiveUser() == nil {
|
||||
fmt.Println("未登录账号")
|
||||
return nil
|
||||
}
|
||||
if IsFamilyCloud(config.Config.ActiveUser().ActiveFamilyId) {
|
||||
fmt.Println("家庭云不支持复制操作")
|
||||
return nil
|
||||
}
|
||||
RunCopy(c.Args()...)
|
||||
return nil
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func CmdMv() cli.Command {
|
||||
return cli.Command{
|
||||
Name: "mv",
|
||||
Usage: "移动文件/目录",
|
||||
UsageText: `移动:
|
||||
cloudpan189-go mv <文件/目录1> <文件/目录2> <文件/目录3> ... <目标目录>`,
|
||||
Description: `
|
||||
注意: 移动多个文件和目录时, 请确保每一个文件和目录都存在, 否则移动操作会失败.
|
||||
|
||||
示例:
|
||||
|
||||
将 /我的资源/1.mp4 移动到 根目录 /
|
||||
cloudpan189-go mv /我的资源/1.mp4 /
|
||||
`,
|
||||
Category: "天翼云盘",
|
||||
Before: cmder.ReloadConfigFunc,
|
||||
Action: func(c *cli.Context) error {
|
||||
if c.NArg() <= 1 {
|
||||
cli.ShowCommandHelp(c, c.Command.Name)
|
||||
return nil
|
||||
}
|
||||
if config.Config.ActiveUser() == nil {
|
||||
fmt.Println("未登录账号")
|
||||
return nil
|
||||
}
|
||||
|
||||
RunMove(parseFamilyId(c), c.Args()...)
|
||||
return nil
|
||||
},
|
||||
Flags: []cli.Flag{
|
||||
cli.StringFlag{
|
||||
Name: "familyId",
|
||||
Usage: "家庭云ID",
|
||||
Value: "",
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
// RunCopy 执行复制文件/目录
|
||||
func RunCopy(paths ...string) {
|
||||
// 只支持个人云
|
||||
|
|
|
@ -17,6 +17,7 @@ import (
|
|||
"fmt"
|
||||
"github.com/tickstep/cloudpan189-api/cloudpan"
|
||||
"github.com/tickstep/cloudpan189-api/cloudpan/apierror"
|
||||
"github.com/tickstep/cloudpan189-go/cmder"
|
||||
"github.com/tickstep/cloudpan189-go/cmder/cmdtable"
|
||||
"github.com/tickstep/cloudpan189-go/internal/config"
|
||||
"github.com/tickstep/cloudpan189-go/internal/file/downloader"
|
||||
|
@ -24,6 +25,7 @@ import (
|
|||
"github.com/tickstep/cloudpan189-go/internal/taskframework"
|
||||
"github.com/tickstep/library-go/converter"
|
||||
"github.com/tickstep/cloudpan189-go/library/requester/transfer"
|
||||
"github.com/urfave/cli"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"runtime"
|
||||
|
@ -58,6 +60,120 @@ var (
|
|||
DownloadCacheSize = 64 * converter.KB
|
||||
)
|
||||
|
||||
func CmdDownload() cli.Command {
|
||||
return cli.Command{
|
||||
Name: "download",
|
||||
Aliases: []string{"d"},
|
||||
Usage: "下载文件/目录",
|
||||
UsageText: cmder.App().Name + " download <文件/目录路径1> <文件/目录2> <文件/目录3> ...",
|
||||
Description: `
|
||||
下载的文件默认保存到, 程序所在目录的 download/ 目录.
|
||||
通过 cloudpan189-go config set -savedir <savedir>, 自定义保存的目录.
|
||||
支持多个文件或目录下载.
|
||||
自动跳过下载重名的文件!
|
||||
|
||||
示例:
|
||||
|
||||
设置保存目录, 保存到 D:\Downloads
|
||||
注意区别反斜杠 "\" 和 斜杠 "/" !!!
|
||||
cloudpan189-go config set -savedir D:\\Downloads
|
||||
或者
|
||||
cloudpan189-go config set -savedir D:/Downloads
|
||||
|
||||
下载 /我的资源/1.mp4
|
||||
cloudpan189-go d /我的资源/1.mp4
|
||||
|
||||
下载 /我的资源 整个目录!!
|
||||
cloudpan189-go d /我的资源
|
||||
|
||||
下载 /我的资源/1.mp4 并保存下载的文件到本地的 d:/panfile
|
||||
cloudpan189-go d --saveto d:/panfile /我的资源/1.mp4
|
||||
`,
|
||||
Category: "天翼云盘",
|
||||
Before: cmder.ReloadConfigFunc,
|
||||
Action: func(c *cli.Context) error {
|
||||
if c.NArg() == 0 {
|
||||
cli.ShowCommandHelp(c, c.Command.Name)
|
||||
return nil
|
||||
}
|
||||
|
||||
// 处理saveTo
|
||||
var (
|
||||
saveTo string
|
||||
)
|
||||
if c.Bool("save") {
|
||||
saveTo = "."
|
||||
} else if c.String("saveto") != "" {
|
||||
saveTo = filepath.Clean(c.String("saveto"))
|
||||
}
|
||||
|
||||
do := &DownloadOptions{
|
||||
IsPrintStatus: c.Bool("status"),
|
||||
IsExecutedPermission: c.Bool("x"),
|
||||
IsOverwrite: c.Bool("ow"),
|
||||
SaveTo: saveTo,
|
||||
Parallel: c.Int("p"),
|
||||
Load: c.Int("l"),
|
||||
MaxRetry: c.Int("retry"),
|
||||
NoCheck: c.Bool("nocheck"),
|
||||
ShowProgress: !c.Bool("np"),
|
||||
FamilyId: parseFamilyId(c),
|
||||
}
|
||||
|
||||
RunDownload(c.Args(), do)
|
||||
return nil
|
||||
},
|
||||
Flags: []cli.Flag{
|
||||
cli.BoolFlag{
|
||||
Name: "ow",
|
||||
Usage: "overwrite, 覆盖已存在的文件",
|
||||
},
|
||||
cli.BoolFlag{
|
||||
Name: "status",
|
||||
Usage: "输出所有线程的工作状态",
|
||||
},
|
||||
cli.BoolFlag{
|
||||
Name: "save",
|
||||
Usage: "将下载的文件直接保存到当前工作目录",
|
||||
},
|
||||
cli.StringFlag{
|
||||
Name: "saveto",
|
||||
Usage: "将下载的文件直接保存到指定的目录",
|
||||
},
|
||||
cli.BoolFlag{
|
||||
Name: "x",
|
||||
Usage: "为文件加上执行权限, (windows系统无效)",
|
||||
},
|
||||
cli.IntFlag{
|
||||
Name: "p",
|
||||
Usage: "指定下载线程数",
|
||||
},
|
||||
cli.IntFlag{
|
||||
Name: "l",
|
||||
Usage: "指定同时进行下载文件的数量",
|
||||
},
|
||||
cli.IntFlag{
|
||||
Name: "retry",
|
||||
Usage: "下载失败最大重试次数",
|
||||
Value: pandownload.DefaultDownloadMaxRetry,
|
||||
},
|
||||
cli.BoolFlag{
|
||||
Name: "nocheck",
|
||||
Usage: "下载文件完成后不校验文件",
|
||||
},
|
||||
cli.BoolFlag{
|
||||
Name: "np",
|
||||
Usage: "no progress 不展示下载进度条",
|
||||
},
|
||||
cli.StringFlag{
|
||||
Name: "familyId",
|
||||
Usage: "家庭云ID",
|
||||
Value: "",
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func downloadPrintFormat(load int) string {
|
||||
if load <= 1 {
|
||||
return pandownload.DefaultPrintFormat
|
||||
|
|
|
@ -18,8 +18,10 @@ import (
|
|||
"fmt"
|
||||
"github.com/tickstep/cloudpan189-api/cloudpan"
|
||||
"github.com/tickstep/cloudpan189-api/cloudpan/apierror"
|
||||
"github.com/tickstep/cloudpan189-go/cmder"
|
||||
"github.com/tickstep/cloudpan189-go/internal/config"
|
||||
"github.com/tickstep/library-go/logger"
|
||||
"github.com/urfave/cli"
|
||||
"log"
|
||||
"os"
|
||||
"path"
|
||||
|
@ -36,6 +38,53 @@ type (
|
|||
}
|
||||
)
|
||||
|
||||
func CmdExport() cli.Command {
|
||||
return cli.Command{
|
||||
Name: "export",
|
||||
Usage: "导出文件/目录元数据",
|
||||
UsageText: cmder.App().Name + " export <网盘文件/目录的路径1> <文件/目录2> <文件/目录3> ... <本地保存文件路径>",
|
||||
Description: `
|
||||
导出指定文件/目录下面的所有文件的元数据信息,并保存到指定的本地文件里面。导出的文件元信息可以使用 import 命令(秒传文件功能)导入到网盘中。
|
||||
支持多个文件或目录的导出.
|
||||
|
||||
示例:
|
||||
|
||||
导出 /我的资源/1.mp4 元数据到文件 /Users/tickstep/Downloads/export_files.txt
|
||||
cloudpan189-go export /我的资源/1.mp4 /Users/tickstep/Downloads/export_files.txt
|
||||
|
||||
导出 /我的资源 整个目录 元数据到文件 /Users/tickstep/Downloads/export_files.txt
|
||||
cloudpan189-go export /我的资源 /Users/tickstep/Downloads/export_files.txt
|
||||
|
||||
导出 网盘 整个目录 元数据到文件 /Users/tickstep/Downloads/export_files.txt
|
||||
cloudpan189-go export / /Users/tickstep/Downloads/export_files.txt
|
||||
`,
|
||||
Category: "天翼云盘",
|
||||
Before: cmder.ReloadConfigFunc,
|
||||
Action: func(c *cli.Context) error {
|
||||
if c.NArg() < 2 {
|
||||
cli.ShowCommandHelp(c, c.Command.Name)
|
||||
return nil
|
||||
}
|
||||
|
||||
subArgs := c.Args()
|
||||
RunExportFiles(parseFamilyId(c), c.Bool("ow"), subArgs[:len(subArgs)-1], subArgs[len(subArgs)-1])
|
||||
return nil
|
||||
},
|
||||
Flags: []cli.Flag{
|
||||
cli.BoolFlag{
|
||||
Name: "ow",
|
||||
Usage: "overwrite, 覆盖已存在的导出文件",
|
||||
},
|
||||
cli.StringFlag{
|
||||
Name: "familyId",
|
||||
Usage: "家庭云ID",
|
||||
Value: "",
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
func RunExportFiles(familyId int64, overwrite bool, panPaths []string, saveLocalFilePath string) {
|
||||
activeUser := config.Config.ActiveUser()
|
||||
panClient := activeUser.PanClient()
|
||||
|
|
|
@ -17,12 +17,41 @@ import (
|
|||
"fmt"
|
||||
"github.com/olekukonko/tablewriter"
|
||||
"github.com/tickstep/cloudpan189-api/cloudpan"
|
||||
"github.com/tickstep/cloudpan189-go/cmder"
|
||||
"github.com/tickstep/cloudpan189-go/cmder/cmdtable"
|
||||
"github.com/tickstep/cloudpan189-go/internal/config"
|
||||
"github.com/urfave/cli"
|
||||
"strconv"
|
||||
"strings"
|
||||
)
|
||||
|
||||
func CmdFamily() cli.Command {
|
||||
return cli.Command{
|
||||
Name: "family",
|
||||
Usage: "切换云工作模式(家庭云/个人云)",
|
||||
Description: `
|
||||
切换已登录的天翼帐号的云工作模式(家庭云/个人云)
|
||||
如果运行该条命令没有提供参数, 程序将会列出所有的家庭云, 供选择切换.
|
||||
|
||||
示例:
|
||||
cloudpan189-go family
|
||||
cloudpan189-go family <familyId>
|
||||
`,
|
||||
Category: "天翼云盘账号",
|
||||
Before: cmder.ReloadConfigFunc,
|
||||
After: cmder.SaveConfigFunc,
|
||||
Action: func(c *cli.Context) error {
|
||||
inputData := c.Args().Get(0)
|
||||
targetFamilyId := int64(-1)
|
||||
if inputData != "" && len(inputData) > 0 {
|
||||
targetFamilyId, _ = strconv.ParseInt(inputData, 10, 0)
|
||||
}
|
||||
RunSwitchFamilyList(targetFamilyId)
|
||||
return nil
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func RunSwitchFamilyList(targetFamilyId int64) {
|
||||
currentFamilyId := config.Config.ActiveUser().ActiveFamilyId
|
||||
var activeFamilyInfo *cloudpan.AppFamilyInfo = nil
|
||||
|
|
|
@ -18,12 +18,15 @@ import (
|
|||
"fmt"
|
||||
"github.com/tickstep/cloudpan189-api/cloudpan"
|
||||
"github.com/tickstep/cloudpan189-api/cloudpan/apierror"
|
||||
"github.com/tickstep/cloudpan189-go/cmder"
|
||||
"github.com/tickstep/cloudpan189-go/internal/config"
|
||||
"github.com/tickstep/library-go/logger"
|
||||
"github.com/urfave/cli"
|
||||
"io/ioutil"
|
||||
"log"
|
||||
"os"
|
||||
"path"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
@ -39,6 +42,66 @@ const (
|
|||
DefaultSaveToPanPath = "/cloudpan189-go"
|
||||
)
|
||||
|
||||
func CmdImport() cli.Command {
|
||||
return cli.Command{
|
||||
Name: "import",
|
||||
Usage: "导入文件",
|
||||
UsageText: cmder.App().Name + " export <本地元数据文件路径>",
|
||||
Description: `
|
||||
导入文件中记录的元数据文件到网盘。保存到网盘的文件会使用文件元数据记录的路径位置,如果没有指定云盘目录(saveto)则默认导入到目录 cloudpan189-go 中。
|
||||
导入的文件可以使用 export 命令获得。
|
||||
|
||||
导入文件每一行是一个文件元数据,样例如下:
|
||||
{"md5":"3F9EEEBC4E583574D9D64A75E5061E56","size":6365224,"path":"/test/file.dmg"}
|
||||
|
||||
注意:导入文件依赖秒传功能,即会消耗你每日上传文件的限额,如果你导入的文件过多达到每日限额,则剩余的文件无法在当日完成导入。
|
||||
|
||||
示例:
|
||||
|
||||
导入文件 /Users/tickstep/Downloads/export_files.txt
|
||||
cloudpan189-go import /Users/tickstep/Downloads/export_files.txt
|
||||
|
||||
导入文件 /Users/tickstep/Downloads/export_files.txt 并保存到目录 /my2020 中
|
||||
cloudpan189-go import -saveto=/my2020 /Users/tickstep/Downloads/export_files.txt
|
||||
|
||||
导入文件 /Users/tickstep/Downloads/export_files.txt 并保存到网盘根目录 / 中
|
||||
cloudpan189-go import -saveto=/ /Users/tickstep/Downloads/export_files.txt
|
||||
`,
|
||||
Category: "天翼云盘",
|
||||
Before: cmder.ReloadConfigFunc,
|
||||
Action: func(c *cli.Context) error {
|
||||
if c.NArg() < 1 {
|
||||
cli.ShowCommandHelp(c, c.Command.Name)
|
||||
return nil
|
||||
}
|
||||
|
||||
saveTo := ""
|
||||
if c.String("saveto") != "" {
|
||||
saveTo = filepath.Clean(c.String("saveto"))
|
||||
}
|
||||
|
||||
subArgs := c.Args()
|
||||
RunImportFiles(parseFamilyId(c), c.Bool("ow"), saveTo, subArgs[0])
|
||||
return nil
|
||||
},
|
||||
Flags: []cli.Flag{
|
||||
cli.BoolFlag{
|
||||
Name: "ow",
|
||||
Usage: "overwrite, 覆盖已存在的网盘文件",
|
||||
},
|
||||
cli.StringFlag{
|
||||
Name: "familyId",
|
||||
Usage: "家庭云ID",
|
||||
Value: "",
|
||||
},
|
||||
cli.StringFlag{
|
||||
Name: "saveto",
|
||||
Usage: "将文件保存到指定的目录",
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func RunImportFiles(familyId int64, overwrite bool, panSavePath, localFilePath string) {
|
||||
lfi,_ := os.Stat(localFilePath)
|
||||
if lfi != nil {
|
||||
|
|
|
@ -16,79 +16,118 @@ package command
|
|||
import (
|
||||
"fmt"
|
||||
"github.com/tickstep/cloudpan189-api/cloudpan"
|
||||
"github.com/tickstep/cloudpan189-api/cloudpan/apierror"
|
||||
"github.com/tickstep/cloudpan189-go/cmder/cmdliner"
|
||||
"github.com/tickstep/library-go/logger"
|
||||
"github.com/tickstep/cloudpan189-go/cmder"
|
||||
"github.com/tickstep/cloudpan189-go/internal/config"
|
||||
_ "github.com/tickstep/library-go/requester"
|
||||
"github.com/urfave/cli"
|
||||
)
|
||||
|
||||
func RunLogin(username, password string) (usernameStr, passwordStr string, webToken cloudpan.WebLoginToken, appToken cloudpan.AppLoginToken, error error) {
|
||||
line := cmdliner.NewLiner()
|
||||
defer line.Close()
|
||||
|
||||
if username == "" {
|
||||
username, error = line.State.Prompt("请输入用户名(手机号/邮箱/别名), 回车键提交 > ")
|
||||
if error != nil {
|
||||
return
|
||||
}
|
||||
}
|
||||
func CmdLogin() cli.Command {
|
||||
return cli.Command{
|
||||
Name: "login",
|
||||
Usage: "登录天翼云盘账号",
|
||||
Description: `
|
||||
示例:
|
||||
cloudpan189-go login
|
||||
cloudpan189-go login -username=tickstep -password=123xxx
|
||||
|
||||
if password == "" {
|
||||
// liner 的 PasswordPrompt 不安全, 拆行之后密码就会显示出来了
|
||||
fmt.Printf("请输入密码(输入的密码无回显, 确认输入完成, 回车提交即可) > ")
|
||||
password, error = line.State.PasswordPrompt("")
|
||||
if error != nil {
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
// app login
|
||||
atoken, apperr := cloudpan.AppLogin(username, password)
|
||||
if apperr != nil {
|
||||
fmt.Println("APP登录失败:", apperr)
|
||||
return "", "", webToken, appToken, fmt.Errorf("登录失败")
|
||||
}
|
||||
|
||||
// web cookie
|
||||
wtoken := &cloudpan.WebLoginToken{}
|
||||
cookieLoginUser := cloudpan.RefreshCookieToken(atoken.SessionKey)
|
||||
if cookieLoginUser != "" {
|
||||
logger.Verboseln("get COOKIE_LOGIN_USER by session key")
|
||||
wtoken.CookieLoginUser = cookieLoginUser
|
||||
} else {
|
||||
// try login directly
|
||||
wtoken, apperr = cloudpan.Login(username, password)
|
||||
if apperr != nil {
|
||||
if apperr.Code == apierror.ApiCodeNeedCaptchaCode {
|
||||
for i := 0; i < 10; i++ {
|
||||
// 需要认证码
|
||||
savePath, apiErr := cloudpan.GetCaptchaImage()
|
||||
if apiErr != nil {
|
||||
fmt.Errorf("获取认证码错误")
|
||||
return "", "", webToken, appToken, apiErr
|
||||
}
|
||||
fmt.Printf("打开以下路径, 以查看验证码\n%s\n\n", savePath)
|
||||
vcode, err := line.State.Prompt("请输入验证码 > ")
|
||||
if err != nil {
|
||||
return "", "", webToken, appToken, err
|
||||
}
|
||||
wtoken, apiErr = cloudpan.LoginWithCaptcha(username, password, vcode)
|
||||
if apiErr != nil {
|
||||
return "", "", webToken, appToken, apiErr
|
||||
} else {
|
||||
return
|
||||
}
|
||||
常规登录:
|
||||
按提示一步一步来即可.
|
||||
`,
|
||||
Category: "天翼云盘账号",
|
||||
Before: cmder.ReloadConfigFunc, // 每次进行登录动作的时候需要调用刷新配置
|
||||
After: cmder.SaveConfigFunc, // 登录完成需要调用保存配置
|
||||
Action: func(c *cli.Context) error {
|
||||
appToken := cloudpan.AppLoginToken{}
|
||||
webToken := cloudpan.WebLoginToken{}
|
||||
username := ""
|
||||
passowrd := ""
|
||||
if c.IsSet("COOKIE_LOGIN_USER") {
|
||||
webToken.CookieLoginUser = c.String("COOKIE_LOGIN_USER")
|
||||
} else if c.NArg() == 0 {
|
||||
var err error
|
||||
username, passowrd, webToken, appToken, err = RunLogin(c.String("username"), c.String("password"))
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
return err
|
||||
}
|
||||
|
||||
} else {
|
||||
return "", "", webToken, appToken, fmt.Errorf("登录失败")
|
||||
cli.ShowCommandHelp(c, c.Command.Name)
|
||||
return nil
|
||||
}
|
||||
}
|
||||
cloudUser, _ := config.SetupUserByCookie(&webToken, &appToken)
|
||||
// save username / password
|
||||
cloudUser.LoginUserName = config.EncryptString(username)
|
||||
cloudUser.LoginUserPassword = config.EncryptString(passowrd)
|
||||
config.Config.SetActiveUser(cloudUser)
|
||||
fmt.Println("天翼帐号登录成功: ", cloudUser.Nickname)
|
||||
return nil
|
||||
},
|
||||
// 命令的附加options参数说明,使用 help login 命令即可查看
|
||||
Flags: []cli.Flag{
|
||||
cli.StringFlag{
|
||||
Name: "username",
|
||||
Usage: "登录天翼帐号的用户名(手机号/邮箱/别名)",
|
||||
},
|
||||
cli.StringFlag{
|
||||
Name: "password",
|
||||
Usage: "登录天翼帐号的用户密码",
|
||||
},
|
||||
// 暂不支持
|
||||
// cloudpan189-go login -COOKIE_LOGIN_USER=8B12CBBCE89CA8DFC3445985B63B511B5E7EC7...
|
||||
//cli.StringFlag{
|
||||
// Name: "COOKIE_LOGIN_USER",
|
||||
// Usage: "使用 COOKIE_LOGIN_USER cookie来登录帐号",
|
||||
//},
|
||||
},
|
||||
}
|
||||
|
||||
webToken = *wtoken
|
||||
appToken = *atoken
|
||||
usernameStr = username
|
||||
passwordStr = password
|
||||
return
|
||||
}
|
||||
|
||||
func CmdLogout() cli.Command {
|
||||
return cli.Command{
|
||||
Name: "logout",
|
||||
Usage: "退出天翼帐号",
|
||||
Description: "退出当前登录的帐号",
|
||||
Category: "天翼云盘账号",
|
||||
Before: cmder.ReloadConfigFunc,
|
||||
After: cmder.SaveConfigFunc,
|
||||
Action: func(c *cli.Context) error {
|
||||
if config.Config.NumLogins() == 0 {
|
||||
fmt.Println("未设置任何帐号, 不能退出")
|
||||
return nil
|
||||
}
|
||||
|
||||
var (
|
||||
confirm string
|
||||
activeUser = config.Config.ActiveUser()
|
||||
)
|
||||
|
||||
if !c.Bool("y") {
|
||||
fmt.Printf("确认退出当前帐号: %s ? (y/n) > ", activeUser.Nickname)
|
||||
_, err := fmt.Scanln(&confirm)
|
||||
if err != nil || (confirm != "y" && confirm != "Y") {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
deletedUser, err := config.Config.DeleteUser(activeUser.UID)
|
||||
if err != nil {
|
||||
fmt.Printf("退出用户 %s, 失败, 错误: %s\n", activeUser.Nickname, err)
|
||||
}
|
||||
|
||||
fmt.Printf("退出用户成功: %s\n", deletedUser.Nickname)
|
||||
return nil
|
||||
},
|
||||
Flags: []cli.Flag{
|
||||
cli.BoolFlag{
|
||||
Name: "y",
|
||||
Usage: "确认退出帐号",
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func RunLogin(username, password string) (usernameStr, passwordStr string, webToken cloudpan.WebLoginToken, appToken cloudpan.AppLoginToken, error error) {
|
||||
return cmder.DoLoginHelper(username, password)
|
||||
}
|
||||
|
|
|
@ -17,10 +17,12 @@ import (
|
|||
"fmt"
|
||||
"github.com/olekukonko/tablewriter"
|
||||
"github.com/tickstep/cloudpan189-api/cloudpan"
|
||||
"github.com/tickstep/cloudpan189-go/cmder"
|
||||
"github.com/tickstep/cloudpan189-go/cmder/cmdtable"
|
||||
"github.com/tickstep/cloudpan189-go/internal/config"
|
||||
"github.com/tickstep/library-go/converter"
|
||||
"github.com/tickstep/library-go/text"
|
||||
"github.com/urfave/cli"
|
||||
"os"
|
||||
"strconv"
|
||||
)
|
||||
|
@ -43,6 +45,101 @@ const (
|
|||
opSearch
|
||||
)
|
||||
|
||||
func CmdLs() cli.Command {
|
||||
return cli.Command{
|
||||
Name: "ls",
|
||||
Aliases: []string{"l", "ll"},
|
||||
Usage: "列出目录",
|
||||
UsageText: cmder.App().Name + " ls <目录>",
|
||||
Description: `
|
||||
列出当前工作目录内的文件和目录, 或指定目录内的文件和目录
|
||||
|
||||
示例:
|
||||
|
||||
列出 我的资源 内的文件和目录
|
||||
cloudpan189-go ls 我的资源
|
||||
|
||||
绝对路径
|
||||
cloudpan189-go ls /我的资源
|
||||
|
||||
降序排序
|
||||
cloudpan189-go ls -desc 我的资源
|
||||
|
||||
按文件大小降序排序
|
||||
cloudpan189-go ls -size -desc 我的资源
|
||||
`,
|
||||
Category: "天翼云盘",
|
||||
Before: cmder.ReloadConfigFunc,
|
||||
Action: func(c *cli.Context) error {
|
||||
if config.Config.ActiveUser() == nil {
|
||||
fmt.Println("未登录账号")
|
||||
return nil
|
||||
}
|
||||
var (
|
||||
orderBy cloudpan.OrderBy = cloudpan.OrderByName
|
||||
orderSort cloudpan.OrderSort = cloudpan.OrderAsc
|
||||
)
|
||||
|
||||
switch {
|
||||
case c.IsSet("asc"):
|
||||
orderSort = cloudpan.OrderAsc
|
||||
case c.IsSet("desc"):
|
||||
orderSort = cloudpan.OrderDesc
|
||||
default:
|
||||
orderSort = cloudpan.OrderAsc
|
||||
}
|
||||
|
||||
switch {
|
||||
case c.IsSet("time"):
|
||||
orderBy = cloudpan.OrderByTime
|
||||
case c.IsSet("name"):
|
||||
orderBy = cloudpan.OrderByName
|
||||
case c.IsSet("size"):
|
||||
orderBy = cloudpan.OrderBySize
|
||||
default:
|
||||
orderBy = cloudpan.OrderByTime
|
||||
}
|
||||
|
||||
RunLs(parseFamilyId(c), c.Args().Get(0), &LsOptions{
|
||||
Total: c.Bool("l") || c.Parent().Args().Get(0) == "ll",
|
||||
}, orderBy, orderSort)
|
||||
|
||||
return nil
|
||||
},
|
||||
Flags: []cli.Flag{
|
||||
cli.BoolFlag{
|
||||
Name: "l",
|
||||
Usage: "详细显示",
|
||||
},
|
||||
cli.BoolFlag{
|
||||
Name: "asc",
|
||||
Usage: "升序排序",
|
||||
},
|
||||
cli.BoolFlag{
|
||||
Name: "desc",
|
||||
Usage: "降序排序",
|
||||
},
|
||||
cli.BoolFlag{
|
||||
Name: "time",
|
||||
Usage: "根据时间排序",
|
||||
},
|
||||
cli.BoolFlag{
|
||||
Name: "name",
|
||||
Usage: "根据文件名排序",
|
||||
},
|
||||
cli.BoolFlag{
|
||||
Name: "size",
|
||||
Usage: "根据大小排序",
|
||||
},
|
||||
cli.StringFlag{
|
||||
Name: "familyId",
|
||||
Usage: "家庭云ID",
|
||||
Value: "",
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func RunLs(familyId int64, targetPath string, lsOptions *LsOptions, orderBy cloudpan.OrderBy, orderSort cloudpan.OrderSort) {
|
||||
activeUser := config.Config.ActiveUser()
|
||||
targetPath = activeUser.PathJoin(familyId, targetPath)
|
||||
|
|
|
@ -17,10 +17,42 @@ import (
|
|||
"fmt"
|
||||
"github.com/tickstep/cloudpan189-api/cloudpan"
|
||||
"github.com/tickstep/cloudpan189-api/cloudpan/apierror"
|
||||
"github.com/tickstep/cloudpan189-go/cmder"
|
||||
"github.com/tickstep/cloudpan189-go/internal/config"
|
||||
"github.com/urfave/cli"
|
||||
"path"
|
||||
"strings"
|
||||
)
|
||||
|
||||
func CmdMkdir() cli.Command {
|
||||
return cli.Command{
|
||||
Name: "mkdir",
|
||||
Usage: "创建目录",
|
||||
UsageText: cmder.App().Name + " mkdir <目录>",
|
||||
Category: "天翼云盘",
|
||||
Before: cmder.ReloadConfigFunc,
|
||||
Action: func(c *cli.Context) error {
|
||||
if c.NArg() == 0 {
|
||||
cli.ShowCommandHelp(c, c.Command.Name)
|
||||
return nil
|
||||
}
|
||||
if config.Config.ActiveUser() == nil {
|
||||
fmt.Println("未登录账号")
|
||||
return nil
|
||||
}
|
||||
RunMkdir(parseFamilyId(c), c.Args().Get(0))
|
||||
return nil
|
||||
},
|
||||
Flags: []cli.Flag{
|
||||
cli.StringFlag{
|
||||
Name: "familyId",
|
||||
Usage: "家庭云ID",
|
||||
Value: "",
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func RunMkdir(familyId int64, name string) {
|
||||
activeUser := GetActiveUser()
|
||||
fullpath := activeUser.PathJoin(familyId, name)
|
||||
|
|
|
@ -13,6 +13,14 @@
|
|||
// limitations under the License.
|
||||
package command
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/tickstep/cloudpan189-go/cmder"
|
||||
"github.com/tickstep/cloudpan189-go/internal/config"
|
||||
"github.com/tickstep/library-go/converter"
|
||||
"github.com/urfave/cli"
|
||||
)
|
||||
|
||||
type QuotaInfo struct {
|
||||
// 已使用个人空间大小
|
||||
UsedSize int64
|
||||
|
@ -20,6 +28,30 @@ type QuotaInfo struct {
|
|||
Quota int64
|
||||
}
|
||||
|
||||
func CmdQuota() cli.Command {
|
||||
return cli.Command{
|
||||
Name: "quota",
|
||||
Usage: "获取当前帐号空间配额",
|
||||
Description: "获取网盘的总储存空间, 和已使用的储存空间",
|
||||
Category: "天翼云盘账号",
|
||||
Before: cmder.ReloadConfigFunc,
|
||||
Action: func(c *cli.Context) error {
|
||||
if config.Config.ActiveUser() == nil {
|
||||
fmt.Println("未登录账号")
|
||||
return nil
|
||||
}
|
||||
q, err := RunGetQuotaInfo()
|
||||
if err == nil {
|
||||
fmt.Printf("账号: %s, uid: %d, 个人空间总额: %s, 个人空间已使用: %s, 比率: %f%%\n",
|
||||
config.Config.ActiveUser().Nickname, config.Config.ActiveUser().UID,
|
||||
converter.ConvertFileSize(q.Quota, 2), converter.ConvertFileSize(q.UsedSize, 2),
|
||||
100*float64(q.UsedSize)/float64(q.Quota))
|
||||
}
|
||||
return nil
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func RunGetQuotaInfo() (quotaInfo *QuotaInfo, error error) {
|
||||
user, err := GetActivePanClient().GetUserInfo()
|
||||
if err != nil {
|
||||
|
|
|
@ -17,12 +17,104 @@ import (
|
|||
"fmt"
|
||||
"github.com/olekukonko/tablewriter"
|
||||
"github.com/tickstep/cloudpan189-api/cloudpan"
|
||||
"github.com/tickstep/cloudpan189-go/cmder"
|
||||
"github.com/tickstep/cloudpan189-go/cmder/cmdtable"
|
||||
"github.com/tickstep/library-go/converter"
|
||||
"github.com/urfave/cli"
|
||||
"os"
|
||||
"strconv"
|
||||
)
|
||||
|
||||
func CmdRecycle() cli.Command {
|
||||
return cli.Command{
|
||||
Name: "recycle",
|
||||
Usage: "回收站",
|
||||
Description: `
|
||||
回收站操作.
|
||||
|
||||
示例:
|
||||
|
||||
1. 从回收站还原两个文件, 其中的两个文件的 file_id 分别为 1013792297798440 和 643596340463870
|
||||
cloudpan189-go recycle restore 1013792297798440 643596340463870
|
||||
|
||||
2. 从回收站删除两个文件, 其中的两个文件的 file_id 分别为 1013792297798440 和 643596340463870
|
||||
cloudpan189-go recycle delete 1013792297798440 643596340463870
|
||||
|
||||
3. 清空回收站, 程序不会进行二次确认, 谨慎操作!!!
|
||||
cloudpan189-go recycle delete -all
|
||||
`,
|
||||
Category: "天翼云盘",
|
||||
Before: cmder.ReloadConfigFunc,
|
||||
Action: func(c *cli.Context) error {
|
||||
if c.NumFlags() <= 0 || c.NArg() <= 0 {
|
||||
cli.ShowCommandHelp(c, c.Command.Name)
|
||||
}
|
||||
return nil
|
||||
},
|
||||
Subcommands: []cli.Command{
|
||||
{
|
||||
Name: "list",
|
||||
Aliases: []string{"ls", "l"},
|
||||
Usage: "列出回收站文件列表",
|
||||
UsageText: cmder.App().Name + " recycle list",
|
||||
Action: func(c *cli.Context) error {
|
||||
RunRecycleList(c.Int("page"))
|
||||
return nil
|
||||
},
|
||||
Flags: []cli.Flag{
|
||||
cli.IntFlag{
|
||||
Name: "page",
|
||||
Usage: "回收站文件列表页数",
|
||||
Value: 1,
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "restore",
|
||||
Aliases: []string{"r"},
|
||||
Usage: "还原回收站文件或目录",
|
||||
UsageText: cmder.App().Name + " recycle restore <file_id 1> <file_id 2> <file_id 3> ...",
|
||||
Description: `根据文件/目录的 fs_id, 还原回收站指定的文件或目录`,
|
||||
Action: func(c *cli.Context) error {
|
||||
if c.NArg() <= 0 {
|
||||
cli.ShowCommandHelp(c, c.Command.Name)
|
||||
return nil
|
||||
}
|
||||
RunRecycleRestore(c.Args()...)
|
||||
return nil
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "delete",
|
||||
Aliases: []string{"d"},
|
||||
Usage: "删除回收站文件或目录 / 清空回收站",
|
||||
UsageText: cmder.App().Name + " recycle delete [-all] <file_id 1> <file_id 2> <file_id 3> ...",
|
||||
Description: `根据文件/目录的 file_id 或 -all 参数, 删除回收站指定的文件或目录或清空回收站`,
|
||||
Action: func(c *cli.Context) error {
|
||||
if c.Bool("all") {
|
||||
// 清空回收站
|
||||
RunRecycleClear()
|
||||
return nil
|
||||
}
|
||||
|
||||
if c.NArg() <= 0 {
|
||||
cli.ShowCommandHelp(c, c.Command.Name)
|
||||
return nil
|
||||
}
|
||||
RunRecycleDelete(c.Args()...)
|
||||
return nil
|
||||
},
|
||||
Flags: []cli.Flag{
|
||||
cli.BoolFlag{
|
||||
Name: "all",
|
||||
Usage: "清空回收站, 程序不会进行二次确认, 谨慎操作!!!",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
// RunRecycleList 执行列出回收站文件列表
|
||||
func RunRecycleList(page int) {
|
||||
if page < 1 {
|
||||
|
|
|
@ -18,10 +18,53 @@ import (
|
|||
"github.com/tickstep/cloudpan189-api/cloudpan"
|
||||
"github.com/tickstep/cloudpan189-api/cloudpan/apierror"
|
||||
"github.com/tickstep/cloudpan189-api/cloudpan/apiutil"
|
||||
"github.com/tickstep/cloudpan189-go/cmder"
|
||||
"github.com/tickstep/cloudpan189-go/internal/config"
|
||||
"github.com/urfave/cli"
|
||||
"path"
|
||||
"strings"
|
||||
)
|
||||
|
||||
func CmdRename() cli.Command {
|
||||
return cli.Command{
|
||||
Name: "rename",
|
||||
Usage: "重命名文件",
|
||||
UsageText: `重命名文件:
|
||||
cloudpan189-go rename <旧文件/目录名> <新文件/目录名>`,
|
||||
Description: `
|
||||
示例:
|
||||
|
||||
将文件 1.mp4 重命名为 2.mp4
|
||||
cloudpan189-go rename 1.mp4 2.mp4
|
||||
|
||||
将文件 /test/1.mp4 重命名为 /test/2.mp4
|
||||
要求必须是同一个文件目录内
|
||||
cloudpan189-go rename /test/1.mp4 /test/2.mp4
|
||||
`,
|
||||
Category: "天翼云盘",
|
||||
Before: cmder.ReloadConfigFunc,
|
||||
Action: func(c *cli.Context) error {
|
||||
if c.NArg() != 2 {
|
||||
cli.ShowCommandHelp(c, c.Command.Name)
|
||||
return nil
|
||||
}
|
||||
if config.Config.ActiveUser() == nil {
|
||||
fmt.Println("未登录账号")
|
||||
return nil
|
||||
}
|
||||
RunRename(parseFamilyId(c), c.Args().Get(0), c.Args().Get(1))
|
||||
return nil
|
||||
},
|
||||
Flags: []cli.Flag{
|
||||
cli.StringFlag{
|
||||
Name: "familyId",
|
||||
Usage: "家庭云ID",
|
||||
Value: "",
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func RunRename(familyId int64, oldName string, newName string) {
|
||||
if oldName == "" {
|
||||
fmt.Println("请指定命名文件")
|
||||
|
|
|
@ -16,14 +16,61 @@ package command
|
|||
import (
|
||||
"fmt"
|
||||
"github.com/tickstep/cloudpan189-api/cloudpan"
|
||||
"github.com/tickstep/cloudpan189-go/cmder"
|
||||
"github.com/tickstep/cloudpan189-go/cmder/cmdtable"
|
||||
"github.com/tickstep/cloudpan189-go/internal/config"
|
||||
"github.com/tickstep/library-go/logger"
|
||||
"github.com/urfave/cli"
|
||||
"os"
|
||||
"path"
|
||||
"strconv"
|
||||
"time"
|
||||
)
|
||||
|
||||
func CmdRm() cli.Command {
|
||||
return cli.Command{
|
||||
Name: "rm",
|
||||
Usage: "删除文件/目录",
|
||||
UsageText: cmder.App().Name + " rm <文件/目录的路径1> <文件/目录2> <文件/目录3> ...",
|
||||
Description: `
|
||||
注意: 删除多个文件和目录时, 请确保每一个文件和目录都存在, 否则删除操作会失败.
|
||||
被删除的文件或目录可在网盘文件回收站找回.
|
||||
|
||||
示例:
|
||||
|
||||
删除 /我的资源/1.mp4
|
||||
cloudpan189-go rm /我的资源/1.mp4
|
||||
|
||||
删除 /我的资源/1.mp4 和 /我的资源/2.mp4
|
||||
cloudpan189-go rm /我的资源/1.mp4 /我的资源/2.mp4
|
||||
|
||||
删除 /我的资源 整个目录 !!
|
||||
cloudpan189-go rm /我的资源
|
||||
`,
|
||||
Category: "天翼云盘",
|
||||
Before: cmder.ReloadConfigFunc,
|
||||
Action: func(c *cli.Context) error {
|
||||
if c.NArg() == 0 {
|
||||
cli.ShowCommandHelp(c, c.Command.Name)
|
||||
return nil
|
||||
}
|
||||
if config.Config.ActiveUser() == nil {
|
||||
fmt.Println("未登录账号")
|
||||
return nil
|
||||
}
|
||||
RunRemove(parseFamilyId(c), c.Args()...)
|
||||
return nil
|
||||
},
|
||||
Flags: []cli.Flag{
|
||||
cli.StringFlag{
|
||||
Name: "familyId",
|
||||
Usage: "家庭云ID",
|
||||
Value: "",
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
// RunRemove 执行 批量删除文件/目录
|
||||
func RunRemove(familyId int64, paths ...string) {
|
||||
if IsFamilyCloud(familyId) {
|
||||
|
|
|
@ -15,6 +15,10 @@ package command
|
|||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/tickstep/cloudpan189-go/cmder"
|
||||
"github.com/tickstep/cloudpan189-go/internal/config"
|
||||
"github.com/tickstep/library-go/converter"
|
||||
"github.com/urfave/cli"
|
||||
"os"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
@ -25,6 +29,138 @@ import (
|
|||
"github.com/tickstep/library-go/text"
|
||||
)
|
||||
|
||||
func CmdShare() cli.Command {
|
||||
return cli.Command{
|
||||
Name: "share",
|
||||
Usage: "分享文件/目录",
|
||||
UsageText: cmder.App().Name + " share",
|
||||
Category: "天翼云盘",
|
||||
Before: cmder.ReloadConfigFunc,
|
||||
Action: func(c *cli.Context) error {
|
||||
cli.ShowCommandHelp(c, c.Command.Name)
|
||||
return nil
|
||||
},
|
||||
Subcommands: []cli.Command{
|
||||
{
|
||||
Name: "set",
|
||||
Aliases: []string{"s"},
|
||||
Usage: "设置分享文件/目录",
|
||||
UsageText: cmder.App().Name + " share set <文件/目录1> <文件/目录2> ...",
|
||||
Description: `
|
||||
示例:
|
||||
|
||||
创建文件 1.mp4 的分享链接
|
||||
cloudpan189-go share set 1.mp4
|
||||
|
||||
创建文件 1.mp4 的分享链接,并指定有效期为1天
|
||||
cloudpan189-go share set -time 1 1.mp4
|
||||
`,
|
||||
Action: func(c *cli.Context) error {
|
||||
if c.NArg() < 1 {
|
||||
cli.ShowCommandHelp(c, c.Command.Name)
|
||||
return nil
|
||||
}
|
||||
if config.Config.ActiveUser() == nil {
|
||||
fmt.Println("未登录账号")
|
||||
return nil
|
||||
}
|
||||
if IsFamilyCloud(config.Config.ActiveUser().ActiveFamilyId) {
|
||||
fmt.Println("家庭云不支持文件分享,请切换到个人云")
|
||||
return nil
|
||||
}
|
||||
et := cloudpan.ShareExpiredTimeForever
|
||||
if c.IsSet("time") {
|
||||
op := c.String("time")
|
||||
if op == "1" {
|
||||
et = cloudpan.ShareExpiredTime1Day
|
||||
} else if op == "2" {
|
||||
et = cloudpan.ShareExpiredTime7Day
|
||||
} else {
|
||||
et = cloudpan.ShareExpiredTimeForever
|
||||
}
|
||||
}
|
||||
sm := cloudpan.ShareModePrivate
|
||||
if c.IsSet("mode") {
|
||||
op := c.String("mode")
|
||||
if op == "1" {
|
||||
sm = cloudpan.ShareModePrivate
|
||||
} else {
|
||||
sm = cloudpan.ShareModePublic
|
||||
}
|
||||
}
|
||||
RunShareSet(c.Args(), et, sm)
|
||||
return nil
|
||||
},
|
||||
Flags: []cli.Flag{
|
||||
cli.StringFlag{
|
||||
Name: "time",
|
||||
Usage: "有效期,0-永久,1-1天,2-7天",
|
||||
},
|
||||
cli.StringFlag{
|
||||
Name: "mode",
|
||||
Usage: "有效期,1-私密分享,2-公开分享",
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "list",
|
||||
Aliases: []string{"l"},
|
||||
Usage: "列出已分享文件/目录",
|
||||
UsageText: cmder.App().Name + " share list",
|
||||
Action: func(c *cli.Context) error {
|
||||
RunShareList(c.Int("page"))
|
||||
return nil
|
||||
},
|
||||
Flags: []cli.Flag{
|
||||
cli.IntFlag{
|
||||
Name: "page",
|
||||
Usage: "分享列表的页数",
|
||||
Value: 1,
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "cancel",
|
||||
Aliases: []string{"c"},
|
||||
Usage: "取消分享文件/目录",
|
||||
UsageText: cmder.App().Name + " share cancel <shareid_1> <shareid_2> ...",
|
||||
Description: `目前只支持通过分享id (shareid) 来取消分享.`,
|
||||
Action: func(c *cli.Context) error {
|
||||
if c.NArg() < 1 {
|
||||
cli.ShowCommandHelp(c, c.Command.Name)
|
||||
return nil
|
||||
}
|
||||
RunShareCancel(converter.SliceStringToInt64(c.Args()))
|
||||
return nil
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "save",
|
||||
Usage: "转存分享的全部文件到指定文件夹",
|
||||
UsageText: cmder.App().Name + " share save [save_dir_path] \"[share_url]\"",
|
||||
Description: `转存分享的全部文件到指定文件夹
|
||||
示例:
|
||||
将 https://cloud.189.cn/t/RzUNre7nq2Uf 分享链接里面的全部文件转存到 /我的文档 这个网盘目录里面
|
||||
注意:转存需要一定的时间才能生效,需要等待一会才能完全转存到网盘文件夹里面
|
||||
cloudpan189-go share save /我的文档 https://cloud.189.cn/t/RzUNre7nq2Uf(访问码:io7x)
|
||||
`,
|
||||
Action: func(c *cli.Context) error {
|
||||
if c.NArg() < 2 {
|
||||
cli.ShowCommandHelp(c, c.Command.Name)
|
||||
return nil
|
||||
}
|
||||
if config.Config.ActiveUser() == nil {
|
||||
fmt.Println("未登录账号")
|
||||
return nil
|
||||
}
|
||||
RunShareSave(c.Args().Get(1), c.Args().Get(0))
|
||||
return nil
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
// RunShareSet 执行分享
|
||||
func RunShareSet(paths []string, expiredTime cloudpan.ShareExpiredTime, shareMode cloudpan.ShareMode) {
|
||||
fileList, _, err := GetFileInfoByPaths(paths[:len(paths)]...)
|
||||
|
|
|
@ -15,6 +15,7 @@ package command
|
|||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/tickstep/cloudpan189-go/cmder"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"path"
|
||||
|
@ -98,6 +99,109 @@ var UploadFlags = []cli.Flag{
|
|||
},
|
||||
}
|
||||
|
||||
func CmdUpload() cli.Command {
|
||||
return cli.Command{
|
||||
Name: "upload",
|
||||
Aliases: []string{"u"},
|
||||
Usage: "上传文件/目录",
|
||||
UsageText: cmder.App().Name + " upload <本地文件/目录的路径1> <文件/目录2> <文件/目录3> ... <目标目录>",
|
||||
Description: `
|
||||
上传默认采用分片上传的方式, 上传的文件将会保存到, <目标目录>.
|
||||
|
||||
示例:
|
||||
|
||||
1. 将本地的 C:\Users\Administrator\Desktop\1.mp4 上传到网盘 /视频 目录
|
||||
注意区别反斜杠 "\" 和 斜杠 "/" !!!
|
||||
cloudpan189-go upload C:/Users/Administrator/Desktop/1.mp4 /视频
|
||||
|
||||
2. 将本地的 C:\Users\Administrator\Desktop\1.mp4 和 C:\Users\Administrator\Desktop\2.mp4 上传到网盘 /视频 目录
|
||||
cloudpan189-go upload C:/Users/Administrator/Desktop/1.mp4 C:/Users/Administrator/Desktop/2.mp4 /视频
|
||||
|
||||
3. 将本地的 C:\Users\Administrator\Desktop 整个目录上传到网盘 /视频 目录
|
||||
cloudpan189-go upload C:/Users/Administrator/Desktop /视频
|
||||
|
||||
4. 使用相对路径
|
||||
cloudpan189-go upload 1.mp4 /视频
|
||||
|
||||
5. 覆盖上传,已存在的同名文件会被移到回收站
|
||||
cloudpan189-go upload -ow 1.mp4 /视频
|
||||
`,
|
||||
Category: "天翼云盘",
|
||||
Before: cmder.ReloadConfigFunc,
|
||||
Action: func(c *cli.Context) error {
|
||||
if c.NArg() < 2 {
|
||||
cli.ShowCommandHelp(c, c.Command.Name)
|
||||
return nil
|
||||
}
|
||||
|
||||
subArgs := c.Args()
|
||||
RunUpload(subArgs[:c.NArg()-1], subArgs[c.NArg()-1], &UploadOptions{
|
||||
AllParallel: c.Int("p"),
|
||||
Parallel: 1, // 天翼云盘一个文件只支持单线程上传
|
||||
MaxRetry: c.Int("retry"),
|
||||
NoRapidUpload: c.Bool("norapid"),
|
||||
NoSplitFile: true, // 天翼云盘不支持分片并发上传,只支持单线程上传,支持断点续传
|
||||
ShowProgress: !c.Bool("np"),
|
||||
IsOverwrite: c.Bool("ow"),
|
||||
FamilyId: parseFamilyId(c),
|
||||
ExcludeNames: c.StringSlice("exn"),
|
||||
})
|
||||
return nil
|
||||
},
|
||||
Flags: UploadFlags,
|
||||
}
|
||||
}
|
||||
|
||||
func CmdRapidUpload() cli.Command {
|
||||
return cli.Command{
|
||||
Name: "rapidupload",
|
||||
Aliases: []string{"ru"},
|
||||
Usage: "手动秒传文件",
|
||||
UsageText: cmder.App().Name + " rapidupload -size=<文件的大小> -md5=<文件的md5值> <保存的网盘路径, 需包含文件名>",
|
||||
Description: `
|
||||
使用此功能秒传文件, 前提是知道文件的大小, md5, 且网盘中存在一模一样的文件.
|
||||
上传的文件将会保存到网盘的目标目录.
|
||||
|
||||
示例:
|
||||
|
||||
1. 如果秒传成功, 则保存到网盘路径 /test/file.txt
|
||||
cloudpan189-go rapidupload -size=56276137 -md5=fbe082d80e90f90f0fb1f94adbbcfa7f /test/file.txt
|
||||
`,
|
||||
Category: "天翼云盘",
|
||||
Before: cmder.ReloadConfigFunc,
|
||||
Action: func(c *cli.Context) error {
|
||||
if c.NArg() <= 0 || !c.IsSet("md5") || !c.IsSet("size") {
|
||||
cli.ShowCommandHelp(c, c.Command.Name)
|
||||
return nil
|
||||
}
|
||||
|
||||
RunRapidUpload(parseFamilyId(c), c.Bool("ow"), c.Args().Get(0), c.String("md5"), c.Int64("size"))
|
||||
return nil
|
||||
},
|
||||
Flags: []cli.Flag{
|
||||
cli.StringFlag{
|
||||
Name: "md5",
|
||||
Usage: "文件的 md5 值",
|
||||
Required: true,
|
||||
},
|
||||
cli.Int64Flag{
|
||||
Name: "size",
|
||||
Usage: "文件的大小",
|
||||
Required: true,
|
||||
},
|
||||
cli.BoolFlag{
|
||||
Name: "ow",
|
||||
Usage: "overwrite, 覆盖已存在的文件",
|
||||
},
|
||||
cli.StringFlag{
|
||||
Name: "familyId",
|
||||
Usage: "家庭云ID",
|
||||
Value: "",
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
// RunUpload 执行文件上传
|
||||
func RunUpload(localPaths []string, savePath string, opt *UploadOptions) {
|
||||
activeUser := GetActiveUser()
|
||||
|
|
|
@ -14,9 +14,136 @@
|
|||
package command
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/tickstep/cloudpan189-api/cloudpan"
|
||||
"github.com/tickstep/cloudpan189-go/cmder"
|
||||
"github.com/tickstep/cloudpan189-go/internal/config"
|
||||
"github.com/urfave/cli"
|
||||
"strconv"
|
||||
)
|
||||
|
||||
func CmdLoglist() cli.Command {
|
||||
return cli.Command{
|
||||
Name: "loglist",
|
||||
Usage: "列出帐号列表",
|
||||
Description: "列出所有已登录的天翼帐号",
|
||||
Category: "天翼云盘账号",
|
||||
Before: cmder.ReloadConfigFunc,
|
||||
Action: func(c *cli.Context) error {
|
||||
fmt.Println(config.Config.UserList.String())
|
||||
return nil
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func CmdSu() cli.Command {
|
||||
return cli.Command{
|
||||
Name: "su",
|
||||
Usage: "切换天翼帐号",
|
||||
Description: `
|
||||
切换已登录的天翼帐号:
|
||||
如果运行该条命令没有提供参数, 程序将会列出所有的帐号, 供选择切换.
|
||||
|
||||
示例:
|
||||
cloudpan189-go su
|
||||
cloudpan189-go su <uid or name>
|
||||
`,
|
||||
Category: "天翼云盘账号",
|
||||
Before: cmder.ReloadConfigFunc,
|
||||
After: cmder.SaveConfigFunc,
|
||||
Action: func(c *cli.Context) error {
|
||||
if c.NArg() >= 2 {
|
||||
cli.ShowCommandHelp(c, c.Command.Name)
|
||||
return nil
|
||||
}
|
||||
|
||||
numLogins := config.Config.NumLogins()
|
||||
|
||||
if numLogins == 0 {
|
||||
fmt.Printf("未设置任何帐号, 不能切换\n")
|
||||
return nil
|
||||
}
|
||||
|
||||
var (
|
||||
inputData = c.Args().Get(0)
|
||||
uid uint64
|
||||
)
|
||||
|
||||
if c.NArg() == 1 {
|
||||
// 直接切换
|
||||
uid, _ = strconv.ParseUint(inputData, 10, 64)
|
||||
} else if c.NArg() == 0 {
|
||||
// 输出所有帐号供选择切换
|
||||
cli.HandleAction(cmder.App().Command("loglist").Action, c)
|
||||
|
||||
// 提示输入 index
|
||||
var index string
|
||||
fmt.Printf("输入要切换帐号的 # 值 > ")
|
||||
_, err := fmt.Scanln(&index)
|
||||
if err != nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
if n, err := strconv.Atoi(index); err == nil && n >= 0 && n < numLogins {
|
||||
uid = config.Config.UserList[n].UID
|
||||
} else {
|
||||
fmt.Printf("切换用户失败, 请检查 # 值是否正确\n")
|
||||
return nil
|
||||
}
|
||||
} else {
|
||||
cli.ShowCommandHelp(c, c.Command.Name)
|
||||
}
|
||||
|
||||
switchedUser, err := config.Config.SwitchUser(uid, inputData)
|
||||
if err != nil {
|
||||
fmt.Printf("切换用户失败, %s\n", err)
|
||||
return nil
|
||||
}
|
||||
|
||||
if switchedUser == nil {
|
||||
switchedUser = cmder.TryLogin()
|
||||
}
|
||||
|
||||
if switchedUser != nil {
|
||||
fmt.Printf("切换用户: %s\n", switchedUser.Nickname)
|
||||
} else {
|
||||
fmt.Printf("切换用户失败\n")
|
||||
}
|
||||
|
||||
return nil
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func CmdWho() cli.Command {
|
||||
return cli.Command{
|
||||
Name: "who",
|
||||
Usage: "获取当前帐号",
|
||||
Description: "获取当前帐号的信息",
|
||||
Category: "天翼云盘账号",
|
||||
Before: cmder.ReloadConfigFunc,
|
||||
Action: func(c *cli.Context) error {
|
||||
if config.Config.ActiveUser() == nil {
|
||||
fmt.Println("未登录账号")
|
||||
return nil
|
||||
}
|
||||
activeUser := config.Config.ActiveUser()
|
||||
gender := "未知"
|
||||
if activeUser.Sex == "F" {
|
||||
gender = "女"
|
||||
} else if activeUser.Sex == "M" {
|
||||
gender = "男"
|
||||
}
|
||||
cloudName := "个人云"
|
||||
if config.Config.ActiveUser().ActiveFamilyId > 0 {
|
||||
cloudName = "家庭云(" + config.Config.ActiveUser().ActiveFamilyInfo.RemarkName + ")"
|
||||
}
|
||||
fmt.Printf("当前帐号 uid: %d, 昵称: %s, 用户名: %s, 性别: %s, 云:%s\n", activeUser.UID, activeUser.Nickname, activeUser.AccountName, gender, cloudName)
|
||||
return nil
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func RunGetUserInfo() (userInfo *cloudpan.UserInfo, error error) {
|
||||
return GetActivePanClient().GetUserInfo()
|
||||
}
|
||||
|
|
|
@ -16,8 +16,29 @@ package command
|
|||
import (
|
||||
"fmt"
|
||||
"github.com/tickstep/cloudpan189-api/cloudpan"
|
||||
"github.com/tickstep/cloudpan189-go/cmder"
|
||||
"github.com/tickstep/cloudpan189-go/internal/config"
|
||||
"github.com/urfave/cli"
|
||||
)
|
||||
|
||||
func CmdSign() cli.Command {
|
||||
return cli.Command{
|
||||
Name: "sign",
|
||||
Usage: "用户签到",
|
||||
Description: "当前帐号进行签到",
|
||||
Category: "天翼云盘账号",
|
||||
Before: cmder.ReloadConfigFunc,
|
||||
Action: func(c *cli.Context) error {
|
||||
if config.Config.ActiveUser() == nil {
|
||||
fmt.Println("未登录账号")
|
||||
return nil
|
||||
}
|
||||
RunUserSign()
|
||||
return nil
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func RunUserSign() {
|
||||
activeUser := GetActiveUser()
|
||||
result, err := activeUser.PanClient().AppUserSign()
|
||||
|
|
|
@ -17,6 +17,9 @@ import (
|
|||
"fmt"
|
||||
"github.com/tickstep/cloudpan189-api/cloudpan"
|
||||
"github.com/tickstep/cloudpan189-api/cloudpan/apierror"
|
||||
"github.com/tickstep/cloudpan189-go/cmder"
|
||||
"github.com/tickstep/cloudpan189-go/internal/config"
|
||||
"github.com/urfave/cli"
|
||||
)
|
||||
|
||||
type (
|
||||
|
@ -31,6 +34,73 @@ const (
|
|||
FamilyCloud FileSourceType = "family"
|
||||
)
|
||||
|
||||
func CmdXcp() cli.Command {
|
||||
return cli.Command{
|
||||
Name: "xcp",
|
||||
Usage: "转存拷贝文件/目录,个人云和家庭云之间转存文件",
|
||||
UsageText: cmder.App().Name + ` xcp <文件/目录>
|
||||
cloudpan189-go xcp <文件/目录1> <文件/目录2> <文件/目录3>`,
|
||||
Description: `
|
||||
注意: 拷贝多个文件和目录时, 请确保每一个文件和目录都存在, 否则拷贝操作会失败. 同样需要保证目标云不存在对应的文件,否则也会操作失败。
|
||||
|
||||
示例:
|
||||
|
||||
当前程序工作在个人云模式下,将 /个人云目录/1.mp4 转存复制到 家庭云根目录中
|
||||
cloudpan189-go xcp /个人云目录/1.mp4
|
||||
|
||||
当前程序工作在家庭云模式下,将 /家庭云目录/1.mp4 和 /家庭云目录/2.mp4 转存复制到 个人云 /来自家庭共享 目录中
|
||||
cloudpan189-go xcp /家庭云目录/1.mp4 /家庭云目录/2.mp4
|
||||
`,
|
||||
Category: "天翼云盘",
|
||||
Before: cmder.ReloadConfigFunc,
|
||||
Action: func(c *cli.Context) error {
|
||||
if c.NArg() <= 0 {
|
||||
cli.ShowCommandHelp(c, c.Command.Name)
|
||||
return nil
|
||||
}
|
||||
if config.Config.ActiveUser() == nil {
|
||||
fmt.Println("未登录账号")
|
||||
return nil
|
||||
}
|
||||
familyId := parseFamilyId(c)
|
||||
fileSource := PersonCloud
|
||||
if c.IsSet("source") {
|
||||
sourceStr := c.String("source")
|
||||
if sourceStr == "person" {
|
||||
fileSource = PersonCloud
|
||||
} else if sourceStr == "family" {
|
||||
fileSource = FamilyCloud
|
||||
} else {
|
||||
fmt.Println("不支持的参数")
|
||||
return nil
|
||||
}
|
||||
} else {
|
||||
if IsFamilyCloud(config.Config.ActiveUser().ActiveFamilyId) {
|
||||
fileSource = FamilyCloud
|
||||
} else {
|
||||
fileSource = PersonCloud
|
||||
}
|
||||
}
|
||||
RunXCopy(fileSource, familyId, c.Args()...)
|
||||
return nil
|
||||
},
|
||||
Flags: []cli.Flag{
|
||||
cli.StringFlag{
|
||||
Name: "familyId",
|
||||
Usage: "家庭云ID",
|
||||
Value: "",
|
||||
Required: false,
|
||||
},
|
||||
cli.StringFlag{
|
||||
Name: "source",
|
||||
Usage: "文件源,person-个人云,family-家庭云",
|
||||
Value: "",
|
||||
Required: false,
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
// RunXCopy 执行移动文件/目录
|
||||
func RunXCopy(source FileSourceType, familyId int64, paths ...string) {
|
||||
activeUser := GetActiveUser()
|
||||
|
|
Loading…
Reference in New Issue