mirror of
https://github.com/truewhile/MeBox.git
synced 2026-10-01 20:16:36 +08:00
feat: add cloud transfer and cache optimizations
This commit is contained in:
@@ -3,8 +3,10 @@ package cloud
|
||||
import (
|
||||
"context"
|
||||
"encoding/base64"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"strconv"
|
||||
"strings"
|
||||
"testing"
|
||||
"time"
|
||||
@@ -62,6 +64,47 @@ func TestQuarkListAndResolve(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestQuarkListPaginates(t *testing.T) {
|
||||
srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
if r.URL.Path != "/file/sort" {
|
||||
t.Fatalf("unexpected path %s", r.URL.Path)
|
||||
}
|
||||
page, _ := strconv.Atoi(r.URL.Query().Get("_page"))
|
||||
w.Write([]byte(`{"status":200,"code":0,"data":{"list":[` + quarkPagePayload(page) + `]}}`))
|
||||
}))
|
||||
defer srv.Close()
|
||||
|
||||
p, err := New(TypeQuark, map[string]any{"cookie": "kps=abc", "base": srv.URL}, srv.Client())
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
entries, err := p.List(context.Background(), "0")
|
||||
if err != nil {
|
||||
t.Fatalf("list: %v", err)
|
||||
}
|
||||
if len(entries) != 101 {
|
||||
t.Fatalf("entries = %d, want 101", len(entries))
|
||||
}
|
||||
if entries[100].ID != "f100" || entries[100].Name != "Movie.100.mkv" {
|
||||
t.Fatalf("last entry wrong: %#v", entries[100])
|
||||
}
|
||||
}
|
||||
|
||||
func quarkPagePayload(page int) string {
|
||||
count := 100
|
||||
offset := 0
|
||||
if page > 1 {
|
||||
count = 1
|
||||
offset = 100
|
||||
}
|
||||
items := make([]string, 0, count)
|
||||
for i := 0; i < count; i++ {
|
||||
n := offset + i
|
||||
items = append(items, fmt.Sprintf(`{"fid":"f%d","file_name":"Movie.%03d.mkv","dir":false,"size":%d}`, n, n, n))
|
||||
}
|
||||
return strings.Join(items, ",")
|
||||
}
|
||||
|
||||
func TestQuarkForce302(t *testing.T) {
|
||||
p := newQuark(map[string]any{"cookie": "c", "force_302": "true"}, http.DefaultClient)
|
||||
if p.proxy {
|
||||
@@ -128,6 +171,41 @@ func Test115ListAndResolve(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func Test115ListPaginates(t *testing.T) {
|
||||
srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
if r.URL.Path != "/files" {
|
||||
t.Fatalf("unexpected path %s", r.URL.Path)
|
||||
}
|
||||
offset, _ := strconv.Atoi(r.URL.Query().Get("offset"))
|
||||
count := 100
|
||||
if offset > 0 {
|
||||
count = 1
|
||||
}
|
||||
items := make([]string, 0, count)
|
||||
for i := 0; i < count; i++ {
|
||||
n := offset + i
|
||||
items = append(items, fmt.Sprintf(`{"fid":"%d","n":"Movie.%03d.mkv","s":%d,"pc":"pick%d"}`, n, n, n, n))
|
||||
}
|
||||
w.Write([]byte(`{"state":true,"data":[` + strings.Join(items, ",") + `]}`))
|
||||
}))
|
||||
defer srv.Close()
|
||||
|
||||
p, err := New(Type115, map[string]any{"cookie": "UID=1; CID=2", "base": srv.URL}, srv.Client())
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
entries, err := p.List(context.Background(), "0")
|
||||
if err != nil {
|
||||
t.Fatalf("list: %v", err)
|
||||
}
|
||||
if len(entries) != 101 {
|
||||
t.Fatalf("entries = %d, want 101", len(entries))
|
||||
}
|
||||
if entries[100].ID != "100" || entries[100].PickCode != "pick100" {
|
||||
t.Fatalf("last entry wrong: %#v", entries[100])
|
||||
}
|
||||
}
|
||||
|
||||
// Test115DownURLEndpointAndError exercises the live fetchDownURLPayload path:
|
||||
// it must POST an m115-encrypted `data` body to /app/chrome/downurl?t=... and
|
||||
// surface 115's error when state=false (no decryption needed for that branch).
|
||||
|
||||
@@ -91,52 +91,59 @@ func (p *pan115Provider) List(ctx context.Context, dirID string) ([]FileEntry, e
|
||||
if dirID == "" {
|
||||
dirID = "0"
|
||||
}
|
||||
q := url.Values{}
|
||||
q.Set("aid", "1")
|
||||
q.Set("cid", dirID)
|
||||
q.Set("o", "user_ptime")
|
||||
q.Set("asc", "0")
|
||||
q.Set("offset", "0")
|
||||
q.Set("show_dir", "1")
|
||||
q.Set("limit", "100")
|
||||
q.Set("format", "json")
|
||||
resp, err := p.get(ctx, p.webBase+"/files?"+q.Encode())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
var r struct {
|
||||
State bool `json:"state"`
|
||||
Error string `json:"error"`
|
||||
Data []struct {
|
||||
Fid string `json:"fid"` // file id (files only)
|
||||
Cid string `json:"cid"` // category id (dirs use this)
|
||||
N string `json:"n"` // name
|
||||
S json.Number `json:"s"` // size
|
||||
Pc string `json:"pc"` // pickcode
|
||||
} `json:"data"`
|
||||
}
|
||||
if err := json.NewDecoder(resp.Body).Decode(&r); err != nil {
|
||||
return nil, fmt.Errorf("115: decode list: %w", err)
|
||||
}
|
||||
if !r.State {
|
||||
return nil, fmt.Errorf("115: list failed: %s", r.Error)
|
||||
}
|
||||
out := make([]FileEntry, 0, len(r.Data))
|
||||
for _, it := range r.Data {
|
||||
isDir := it.Fid == ""
|
||||
id := it.Fid
|
||||
if isDir {
|
||||
id = it.Cid
|
||||
const pageSize = 100
|
||||
out := make([]FileEntry, 0, pageSize)
|
||||
for offset := 0; ; offset += pageSize {
|
||||
q := url.Values{}
|
||||
q.Set("aid", "1")
|
||||
q.Set("cid", dirID)
|
||||
q.Set("o", "user_ptime")
|
||||
q.Set("asc", "0")
|
||||
q.Set("offset", strconv.Itoa(offset))
|
||||
q.Set("show_dir", "1")
|
||||
q.Set("limit", strconv.Itoa(pageSize))
|
||||
q.Set("format", "json")
|
||||
resp, err := p.get(ctx, p.webBase+"/files?"+q.Encode())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
var r struct {
|
||||
State bool `json:"state"`
|
||||
Error string `json:"error"`
|
||||
Data []struct {
|
||||
Fid string `json:"fid"` // file id (files only)
|
||||
Cid string `json:"cid"` // category id (dirs use this)
|
||||
N string `json:"n"` // name
|
||||
S json.Number `json:"s"` // size
|
||||
Pc string `json:"pc"` // pickcode
|
||||
} `json:"data"`
|
||||
}
|
||||
err = json.NewDecoder(resp.Body).Decode(&r)
|
||||
_ = resp.Body.Close()
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("115: decode list: %w", err)
|
||||
}
|
||||
if !r.State {
|
||||
return nil, fmt.Errorf("115: list failed: %s", r.Error)
|
||||
}
|
||||
for _, it := range r.Data {
|
||||
isDir := it.Fid == ""
|
||||
id := it.Fid
|
||||
if isDir {
|
||||
id = it.Cid
|
||||
}
|
||||
size, _ := it.S.Int64()
|
||||
out = append(out, FileEntry{
|
||||
ID: id,
|
||||
Name: it.N,
|
||||
IsDir: isDir,
|
||||
Size: size,
|
||||
PickCode: it.Pc,
|
||||
})
|
||||
}
|
||||
if len(r.Data) < pageSize {
|
||||
break
|
||||
}
|
||||
size, _ := it.S.Int64()
|
||||
out = append(out, FileEntry{
|
||||
ID: id,
|
||||
Name: it.N,
|
||||
IsDir: isDir,
|
||||
Size: size,
|
||||
PickCode: it.Pc,
|
||||
})
|
||||
}
|
||||
return out, nil
|
||||
}
|
||||
|
||||
@@ -7,6 +7,7 @@ import (
|
||||
"fmt"
|
||||
"io"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"strings"
|
||||
)
|
||||
|
||||
@@ -85,38 +86,54 @@ func (q *quarkProvider) List(ctx context.Context, dirID string) ([]FileEntry, er
|
||||
if dirID == "" {
|
||||
dirID = "0"
|
||||
}
|
||||
path := fmt.Sprintf("/file/sort?pr=ucpro&fr=pc&uc_param_str=&pdir_fid=%s&_page=1&_size=100&_fetch_total=1&_sort=file_type:asc,updated_at:desc", dirID)
|
||||
resp, err := q.do(ctx, http.MethodGet, path, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
var r quarkResp
|
||||
if err := json.NewDecoder(resp.Body).Decode(&r); err != nil {
|
||||
return nil, fmt.Errorf("quark: decode list: %w", err)
|
||||
}
|
||||
if r.Code != 0 && r.Status != 200 {
|
||||
return nil, fmt.Errorf("quark: list failed: %s", r.Message)
|
||||
}
|
||||
var data struct {
|
||||
List []struct {
|
||||
Fid string `json:"fid"`
|
||||
FileName string `json:"file_name"`
|
||||
Dir bool `json:"dir"`
|
||||
Size int64 `json:"size"`
|
||||
} `json:"list"`
|
||||
}
|
||||
if err := json.Unmarshal(r.Data, &data); err != nil {
|
||||
return nil, fmt.Errorf("quark: decode list data: %w", err)
|
||||
}
|
||||
out := make([]FileEntry, 0, len(data.List))
|
||||
for _, it := range data.List {
|
||||
out = append(out, FileEntry{
|
||||
ID: it.Fid,
|
||||
Name: it.FileName,
|
||||
IsDir: it.Dir,
|
||||
Size: it.Size,
|
||||
})
|
||||
const pageSize = 100
|
||||
out := make([]FileEntry, 0, pageSize)
|
||||
for page := 1; ; page++ {
|
||||
query := url.Values{}
|
||||
query.Set("pr", "ucpro")
|
||||
query.Set("fr", "pc")
|
||||
query.Set("uc_param_str", "")
|
||||
query.Set("pdir_fid", dirID)
|
||||
query.Set("_page", fmt.Sprint(page))
|
||||
query.Set("_size", fmt.Sprint(pageSize))
|
||||
query.Set("_fetch_total", "1")
|
||||
query.Set("_sort", "file_type:asc,updated_at:desc")
|
||||
path := "/file/sort?" + query.Encode()
|
||||
resp, err := q.do(ctx, http.MethodGet, path, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
var r quarkResp
|
||||
err = json.NewDecoder(resp.Body).Decode(&r)
|
||||
_ = resp.Body.Close()
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("quark: decode list: %w", err)
|
||||
}
|
||||
if r.Code != 0 && r.Status != 200 {
|
||||
return nil, fmt.Errorf("quark: list failed: %s", r.Message)
|
||||
}
|
||||
var data struct {
|
||||
List []struct {
|
||||
Fid string `json:"fid"`
|
||||
FileName string `json:"file_name"`
|
||||
Dir bool `json:"dir"`
|
||||
Size int64 `json:"size"`
|
||||
} `json:"list"`
|
||||
}
|
||||
if err := json.Unmarshal(r.Data, &data); err != nil {
|
||||
return nil, fmt.Errorf("quark: decode list data: %w", err)
|
||||
}
|
||||
for _, it := range data.List {
|
||||
out = append(out, FileEntry{
|
||||
ID: it.Fid,
|
||||
Name: it.FileName,
|
||||
IsDir: it.Dir,
|
||||
Size: it.Size,
|
||||
})
|
||||
}
|
||||
if len(data.List) < pageSize {
|
||||
break
|
||||
}
|
||||
}
|
||||
return out, nil
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user