mirror of https://github.com/Xhofe/alist
				
				
				
			Co-authored-by: Andy Hsu <i@nn.ci>pull/4930/head
							parent
							
								
									8b353da0d2
								
							
						
					
					
						commit
						e5ffd39cf2
					
				| 
						 | 
				
			
			@ -0,0 +1,149 @@
 | 
			
		|||
package _123Share
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"context"
 | 
			
		||||
	"encoding/base64"
 | 
			
		||||
	"fmt"
 | 
			
		||||
	"net/http"
 | 
			
		||||
	"net/url"
 | 
			
		||||
 | 
			
		||||
	"github.com/alist-org/alist/v3/drivers/base"
 | 
			
		||||
	"github.com/alist-org/alist/v3/internal/driver"
 | 
			
		||||
	"github.com/alist-org/alist/v3/internal/errs"
 | 
			
		||||
	"github.com/alist-org/alist/v3/internal/model"
 | 
			
		||||
	"github.com/alist-org/alist/v3/pkg/utils"
 | 
			
		||||
	"github.com/go-resty/resty/v2"
 | 
			
		||||
	log "github.com/sirupsen/logrus"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
type Pan123Share struct {
 | 
			
		||||
	model.Storage
 | 
			
		||||
	Addition
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (d *Pan123Share) Config() driver.Config {
 | 
			
		||||
	return config
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (d *Pan123Share) GetAddition() driver.Additional {
 | 
			
		||||
	return &d.Addition
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (d *Pan123Share) Init(ctx context.Context) error {
 | 
			
		||||
	// TODO login / refresh token
 | 
			
		||||
	//op.MustSaveDriverStorage(d)
 | 
			
		||||
	return nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (d *Pan123Share) Drop(ctx context.Context) error {
 | 
			
		||||
	return nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (d *Pan123Share) List(ctx context.Context, dir model.Obj, args model.ListArgs) ([]model.Obj, error) {
 | 
			
		||||
	// TODO return the files list, required
 | 
			
		||||
	files, err := d.getFiles(dir.GetID())
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, err
 | 
			
		||||
	}
 | 
			
		||||
	return utils.SliceConvert(files, func(src File) (model.Obj, error) {
 | 
			
		||||
		return src, nil
 | 
			
		||||
	})
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (d *Pan123Share) Link(ctx context.Context, file model.Obj, args model.LinkArgs) (*model.Link, error) {
 | 
			
		||||
	// TODO return link of file, required
 | 
			
		||||
	if f, ok := file.(File); ok {
 | 
			
		||||
		//var resp DownResp
 | 
			
		||||
		var headers map[string]string
 | 
			
		||||
		if !utils.IsLocalIPAddr(args.IP) {
 | 
			
		||||
			headers = map[string]string{
 | 
			
		||||
				//"X-Real-IP":       "1.1.1.1",
 | 
			
		||||
				"X-Forwarded-For": args.IP,
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
		data := base.Json{
 | 
			
		||||
			"shareKey":  d.ShareKey,
 | 
			
		||||
			"SharePwd":  d.SharePwd,
 | 
			
		||||
			"etag":      f.Etag,
 | 
			
		||||
			"fileId":    f.FileId,
 | 
			
		||||
			"s3keyFlag": f.S3KeyFlag,
 | 
			
		||||
			"size":      f.Size,
 | 
			
		||||
		}
 | 
			
		||||
		resp, err := d.request(DownloadInfo, http.MethodPost, func(req *resty.Request) {
 | 
			
		||||
			req.SetBody(data).SetHeaders(headers)
 | 
			
		||||
		}, nil)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			return nil, err
 | 
			
		||||
		}
 | 
			
		||||
		downloadUrl := utils.Json.Get(resp, "data", "DownloadURL").ToString()
 | 
			
		||||
		u, err := url.Parse(downloadUrl)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			return nil, err
 | 
			
		||||
		}
 | 
			
		||||
		nu := u.Query().Get("params")
 | 
			
		||||
		if nu != "" {
 | 
			
		||||
			du, _ := base64.StdEncoding.DecodeString(nu)
 | 
			
		||||
			u, err = url.Parse(string(du))
 | 
			
		||||
			if err != nil {
 | 
			
		||||
				return nil, err
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
		u_ := u.String()
 | 
			
		||||
		log.Debug("download url: ", u_)
 | 
			
		||||
		res, err := base.NoRedirectClient.R().SetHeader("Referer", "https://www.123pan.com/").Get(u_)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			return nil, err
 | 
			
		||||
		}
 | 
			
		||||
		log.Debug(res.String())
 | 
			
		||||
		link := model.Link{
 | 
			
		||||
			URL: u_,
 | 
			
		||||
		}
 | 
			
		||||
		log.Debugln("res code: ", res.StatusCode())
 | 
			
		||||
		if res.StatusCode() == 302 {
 | 
			
		||||
			link.URL = res.Header().Get("location")
 | 
			
		||||
		} else if res.StatusCode() < 300 {
 | 
			
		||||
			link.URL = utils.Json.Get(res.Body(), "data", "redirect_url").ToString()
 | 
			
		||||
		}
 | 
			
		||||
		link.Header = http.Header{
 | 
			
		||||
			"Referer": []string{"https://www.123pan.com/"},
 | 
			
		||||
		}
 | 
			
		||||
		return &link, nil
 | 
			
		||||
	}
 | 
			
		||||
	return nil, fmt.Errorf("can't convert obj")
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (d *Pan123Share) MakeDir(ctx context.Context, parentDir model.Obj, dirName string) error {
 | 
			
		||||
	// TODO create folder, optional
 | 
			
		||||
	return errs.NotSupport
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (d *Pan123Share) Move(ctx context.Context, srcObj, dstDir model.Obj) error {
 | 
			
		||||
	// TODO move obj, optional
 | 
			
		||||
	return errs.NotSupport
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (d *Pan123Share) Rename(ctx context.Context, srcObj model.Obj, newName string) error {
 | 
			
		||||
	// TODO rename obj, optional
 | 
			
		||||
	return errs.NotSupport
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (d *Pan123Share) Copy(ctx context.Context, srcObj, dstDir model.Obj) error {
 | 
			
		||||
	// TODO copy obj, optional
 | 
			
		||||
	return errs.NotSupport
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (d *Pan123Share) Remove(ctx context.Context, obj model.Obj) error {
 | 
			
		||||
	// TODO remove obj, optional
 | 
			
		||||
	return errs.NotSupport
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (d *Pan123Share) Put(ctx context.Context, dstDir model.Obj, stream model.FileStreamer, up driver.UpdateProgress) error {
 | 
			
		||||
	// TODO upload file, optional
 | 
			
		||||
	return errs.NotSupport
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
//func (d *Pan123Share) Other(ctx context.Context, args model.OtherArgs) (interface{}, error) {
 | 
			
		||||
//	return nil, errs.NotSupport
 | 
			
		||||
//}
 | 
			
		||||
 | 
			
		||||
var _ driver.Driver = (*Pan123Share)(nil)
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,34 @@
 | 
			
		|||
package _123Share
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"github.com/alist-org/alist/v3/internal/driver"
 | 
			
		||||
	"github.com/alist-org/alist/v3/internal/op"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
type Addition struct {
 | 
			
		||||
	ShareKey string `json:"sharekey" required:"true"`
 | 
			
		||||
	SharePwd string `json:"sharepassword" required:"true"`
 | 
			
		||||
	driver.RootID
 | 
			
		||||
	OrderBy        string `json:"order_by" type:"select" options:"file_name,size,update_at" default:"file_name"`
 | 
			
		||||
	OrderDirection string `json:"order_direction" type:"select" options:"asc,desc" default:"asc"`
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
var config = driver.Config{
 | 
			
		||||
	Name:              "123PanShare",
 | 
			
		||||
	LocalSort:         true,
 | 
			
		||||
	OnlyLocal:         false,
 | 
			
		||||
	OnlyProxy:         false,
 | 
			
		||||
	NoCache:           false,
 | 
			
		||||
	NoUpload:          true,
 | 
			
		||||
	NeedMs:            false,
 | 
			
		||||
	DefaultRoot:       "0",
 | 
			
		||||
	CheckStatus:       false,
 | 
			
		||||
	Alert:             "",
 | 
			
		||||
	NoOverwriteUpload: false,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func init() {
 | 
			
		||||
	op.RegisterDriver(func() driver.Driver {
 | 
			
		||||
		return &Pan123Share{}
 | 
			
		||||
	})
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,91 @@
 | 
			
		|||
package _123Share
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"net/url"
 | 
			
		||||
	"path"
 | 
			
		||||
	"strconv"
 | 
			
		||||
	"strings"
 | 
			
		||||
	"time"
 | 
			
		||||
 | 
			
		||||
	"github.com/alist-org/alist/v3/internal/model"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
type File struct {
 | 
			
		||||
	FileName    string    `json:"FileName"`
 | 
			
		||||
	Size        int64     `json:"Size"`
 | 
			
		||||
	UpdateAt    time.Time `json:"UpdateAt"`
 | 
			
		||||
	FileId      int64     `json:"FileId"`
 | 
			
		||||
	Type        int       `json:"Type"`
 | 
			
		||||
	Etag        string    `json:"Etag"`
 | 
			
		||||
	S3KeyFlag   string    `json:"S3KeyFlag"`
 | 
			
		||||
	DownloadUrl string    `json:"DownloadUrl"`
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (f File) GetPath() string {
 | 
			
		||||
	return ""
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (f File) GetSize() int64 {
 | 
			
		||||
	return f.Size
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (f File) GetName() string {
 | 
			
		||||
	return f.FileName
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (f File) ModTime() time.Time {
 | 
			
		||||
	return f.UpdateAt
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (f File) IsDir() bool {
 | 
			
		||||
	return f.Type == 1
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (f File) GetID() string {
 | 
			
		||||
	return strconv.FormatInt(f.FileId, 10)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (f File) Thumb() string {
 | 
			
		||||
	if f.DownloadUrl == "" {
 | 
			
		||||
		return ""
 | 
			
		||||
	}
 | 
			
		||||
	du, err := url.Parse(f.DownloadUrl)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return ""
 | 
			
		||||
	}
 | 
			
		||||
	du.Path = strings.TrimSuffix(du.Path, "_24_24") + "_70_70"
 | 
			
		||||
	query := du.Query()
 | 
			
		||||
	query.Set("w", "70")
 | 
			
		||||
	query.Set("h", "70")
 | 
			
		||||
	if !query.Has("type") {
 | 
			
		||||
		query.Set("type", strings.TrimPrefix(path.Base(f.FileName), "."))
 | 
			
		||||
	}
 | 
			
		||||
	if !query.Has("trade_key") {
 | 
			
		||||
		query.Set("trade_key", "123pan-thumbnail")
 | 
			
		||||
	}
 | 
			
		||||
	du.RawQuery = query.Encode()
 | 
			
		||||
	return du.String()
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
var _ model.Obj = (*File)(nil)
 | 
			
		||||
var _ model.Thumb = (*File)(nil)
 | 
			
		||||
 | 
			
		||||
//func (f File) Thumb() string {
 | 
			
		||||
//
 | 
			
		||||
//}
 | 
			
		||||
//var _ model.Thumb = (*File)(nil)
 | 
			
		||||
 | 
			
		||||
type Files struct {
 | 
			
		||||
	//BaseResp
 | 
			
		||||
	Data struct {
 | 
			
		||||
		InfoList []File `json:"InfoList"`
 | 
			
		||||
		Next     string `json:"Next"`
 | 
			
		||||
	} `json:"data"`
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
//type DownResp struct {
 | 
			
		||||
//	//BaseResp
 | 
			
		||||
//	Data struct {
 | 
			
		||||
//		DownloadUrl string `json:"DownloadUrl"`
 | 
			
		||||
//	} `json:"data"`
 | 
			
		||||
//}
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,81 @@
 | 
			
		|||
package _123Share
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"errors"
 | 
			
		||||
	"net/http"
 | 
			
		||||
	"strconv"
 | 
			
		||||
 | 
			
		||||
	"github.com/alist-org/alist/v3/drivers/base"
 | 
			
		||||
	"github.com/alist-org/alist/v3/pkg/utils"
 | 
			
		||||
	"github.com/go-resty/resty/v2"
 | 
			
		||||
	jsoniter "github.com/json-iterator/go"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
const (
 | 
			
		||||
	Api          = "https://www.123pan.com/api"
 | 
			
		||||
	AApi         = "https://www.123pan.com/a/api"
 | 
			
		||||
	BApi         = "https://www.123pan.com/b/api"
 | 
			
		||||
	MainApi      = Api
 | 
			
		||||
	FileList     = MainApi + "/share/get"
 | 
			
		||||
	DownloadInfo = MainApi + "/share/download/info"
 | 
			
		||||
	//AuthKeySalt      = "8-8D$sL8gPjom7bk#cY"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
func (d *Pan123Share) request(url string, method string, callback base.ReqCallback, resp interface{}) ([]byte, error) {
 | 
			
		||||
	req := base.RestyClient.R()
 | 
			
		||||
	req.SetHeaders(map[string]string{
 | 
			
		||||
		"origin":      "https://www.123pan.com",
 | 
			
		||||
		"referer":     "https://www.123pan.com/",
 | 
			
		||||
		"user-agent":  "Dart/2.19(dart:io)",
 | 
			
		||||
		"platform":    "android",
 | 
			
		||||
		"app-version": "36",
 | 
			
		||||
	})
 | 
			
		||||
	if callback != nil {
 | 
			
		||||
		callback(req)
 | 
			
		||||
	}
 | 
			
		||||
	if resp != nil {
 | 
			
		||||
		req.SetResult(resp)
 | 
			
		||||
	}
 | 
			
		||||
	res, err := req.Execute(method, url)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, err
 | 
			
		||||
	}
 | 
			
		||||
	body := res.Body()
 | 
			
		||||
	code := utils.Json.Get(body, "code").ToInt()
 | 
			
		||||
	if code != 0 {
 | 
			
		||||
		return nil, errors.New(jsoniter.Get(body, "message").ToString())
 | 
			
		||||
	}
 | 
			
		||||
	return body, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (d *Pan123Share) getFiles(parentId string) ([]File, error) {
 | 
			
		||||
	page := 1
 | 
			
		||||
	res := make([]File, 0)
 | 
			
		||||
	for {
 | 
			
		||||
		var resp Files
 | 
			
		||||
		query := map[string]string{
 | 
			
		||||
			"limit":          "100",
 | 
			
		||||
			"next":           "0",
 | 
			
		||||
			"orderBy":        d.OrderBy,
 | 
			
		||||
			"orderDirection": d.OrderDirection,
 | 
			
		||||
			"parentFileId":   parentId,
 | 
			
		||||
			"Page":           strconv.Itoa(page),
 | 
			
		||||
			"shareKey":       d.ShareKey,
 | 
			
		||||
			"SharePwd":       d.SharePwd,
 | 
			
		||||
		}
 | 
			
		||||
		_, err := d.request(FileList, http.MethodGet, func(req *resty.Request) {
 | 
			
		||||
			req.SetQueryParams(query)
 | 
			
		||||
		}, &resp)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			return nil, err
 | 
			
		||||
		}
 | 
			
		||||
		page++
 | 
			
		||||
		res = append(res, resp.Data.InfoList...)
 | 
			
		||||
		if len(resp.Data.InfoList) == 0 || resp.Data.Next == "-1" {
 | 
			
		||||
			break
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	return res, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// do others that not defined in Driver interface
 | 
			
		||||
| 
						 | 
				
			
			@ -3,6 +3,7 @@ package drivers
 | 
			
		|||
import (
 | 
			
		||||
	_ "github.com/alist-org/alist/v3/drivers/115"
 | 
			
		||||
	_ "github.com/alist-org/alist/v3/drivers/123"
 | 
			
		||||
	_ "github.com/alist-org/alist/v3/drivers/123_share"
 | 
			
		||||
	_ "github.com/alist-org/alist/v3/drivers/139"
 | 
			
		||||
	_ "github.com/alist-org/alist/v3/drivers/189"
 | 
			
		||||
	_ "github.com/alist-org/alist/v3/drivers/189pc"
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
		Reference in New Issue