mirror of
https://github.com/nianzhibai/91.git
synced 2026-06-15 00:44:30 +08:00
7e5e67697e
Implement a new GuangYaPan cloud drive integration across the backend, admin UI, playback proxy, and Spider91 migration flow. Backend changes:\n- Add a GuangYaPan drive driver with token refresh, QR/device login support, directory listing, stream link resolution, directory creation, rename/delete operations, OSS multipart upload, and upload task polling.\n- Register GuangYaPan as a supported storage kind in configuration, catalog normalization, admin APIs, public drive labels, and 302 playback redirects.\n- Allow Spider91 crawler uploads to target GuangYaPan through a dedicated migration adapter.\n- Add scan, thumbnail, preview, and fingerprint cooldown handling for GuangYaPan based on explicit HTTP status codes, Retry-After values, and structured provider codes instead of natural-language message matching.\n- Tighten existing provider cooldown detectors so OneDrive, Google Drive, 115, PikPak, 123pan, Wopan, and media workers avoid treating arbitrary response text as a rate-limit signal.\n- Keep large videos eligible for preview generation unless the user disables preview generation. Admin and tooling changes:\n- Add GuangYaPan as a selectable drive type with QR login UI and token/root-path credential fields.\n- Add crawler upload target support for GuangYaPan in the admin UI.\n- Add drive branding, labels, metadata display, and docs/config examples for GuangYaPan.\n- Include a standalone GuangYaPan QR login helper script for manual credential acquisition. Tests:\n- Add GuangYaPan driver, QR login, proxy, admin API, crawler upload target, fingerprint, cooldown, and form coverage.\n- Update rate-limit tests to assert that message-only throttling text no longer starts cooldowns.\n- Cover explicit HTTP status parsing through shared drive helper tests.
108 lines
3.8 KiB
Go
108 lines
3.8 KiB
Go
package main
|
|
|
|
import (
|
|
"context"
|
|
"io"
|
|
"testing"
|
|
|
|
"github.com/video-site/backend/internal/catalog"
|
|
"github.com/video-site/backend/internal/drives"
|
|
"github.com/video-site/backend/internal/proxy"
|
|
)
|
|
|
|
func TestSpider91IntCredFallbacks(t *testing.T) {
|
|
tests := []struct {
|
|
name string
|
|
d *catalog.Drive
|
|
key string
|
|
def int
|
|
want int
|
|
}{
|
|
{"nil drive", nil, "page", 1, 1},
|
|
{"nil creds", &catalog.Drive{}, "page", 7, 7},
|
|
{"empty value", &catalog.Drive{Credentials: map[string]string{"page": ""}}, "page", 5, 5},
|
|
{"non-numeric", &catalog.Drive{Credentials: map[string]string{"page": "abc"}}, "page", 9, 9},
|
|
{"happy", &catalog.Drive{Credentials: map[string]string{"page": "42"}}, "page", 1, 42},
|
|
{"missing key", &catalog.Drive{Credentials: map[string]string{"a": "1"}}, "b", 99, 99},
|
|
}
|
|
for _, tc := range tests {
|
|
t.Run(tc.name, func(t *testing.T) {
|
|
got := spider91IntCred(tc.d, tc.key, tc.def)
|
|
if got != tc.want {
|
|
t.Fatalf("spider91IntCred(%s) = %d, want %d", tc.name, got, tc.want)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestSpider91UploadDriveIDDoesNotAutoSelectTarget(t *testing.T) {
|
|
reg := proxy.NewRegistry()
|
|
reg.Set("p115-one", &spider91UploadTargetFakeDrive{id: "p115-one", kind: "p115"})
|
|
reg.Set("p123-one", &spider91UploadTargetFakeDrive{id: "p123-one", kind: "p123"})
|
|
reg.Set("onedrive-one", &spider91UploadTargetFakeDrive{id: "onedrive-one", kind: "onedrive"})
|
|
reg.Set("wopan-one", &spider91UploadTargetFakeDrive{id: "wopan-one", kind: "wopan"})
|
|
reg.Set("guangyapan-one", &spider91UploadTargetFakeDrive{id: "guangyapan-one", kind: "guangyapan"})
|
|
|
|
app := &App{registry: reg}
|
|
if got := app.Spider91UploadDriveID(); got != "" {
|
|
t.Fatalf("empty upload target selected %q, want local-only empty target", got)
|
|
}
|
|
|
|
app.spider91UploadDriveID = "p115-one"
|
|
if got := app.Spider91UploadDriveID(); got != "p115-one" {
|
|
t.Fatalf("explicit upload target = %q, want p115-one", got)
|
|
}
|
|
|
|
app.spider91UploadDriveID = "p123-one"
|
|
if got := app.Spider91UploadDriveID(); got != "p123-one" {
|
|
t.Fatalf("explicit p123 upload target = %q, want p123-one", got)
|
|
}
|
|
|
|
app.spider91UploadDriveID = "onedrive-one"
|
|
if got := app.Spider91UploadDriveID(); got != "onedrive-one" {
|
|
t.Fatalf("explicit onedrive upload target = %q, want onedrive-one", got)
|
|
}
|
|
|
|
app.spider91UploadDriveID = "wopan-one"
|
|
if got := app.Spider91UploadDriveID(); got != "wopan-one" {
|
|
t.Fatalf("explicit wopan upload target = %q, want wopan-one", got)
|
|
}
|
|
|
|
app.spider91UploadDriveID = "guangyapan-one"
|
|
if got := app.Spider91UploadDriveID(); got != "guangyapan-one" {
|
|
t.Fatalf("explicit guangyapan upload target = %q, want guangyapan-one", got)
|
|
}
|
|
|
|
app.spider91UploadDriveID = "missing"
|
|
if got := app.Spider91UploadDriveID(); got != "" {
|
|
t.Fatalf("missing upload target = %q, want empty", got)
|
|
}
|
|
}
|
|
|
|
type spider91UploadTargetFakeDrive struct {
|
|
id string
|
|
kind string
|
|
}
|
|
|
|
func (d *spider91UploadTargetFakeDrive) Kind() string { return d.kind }
|
|
func (d *spider91UploadTargetFakeDrive) ID() string { return d.id }
|
|
func (d *spider91UploadTargetFakeDrive) Init(context.Context) error {
|
|
return nil
|
|
}
|
|
func (d *spider91UploadTargetFakeDrive) List(context.Context, string) ([]drives.Entry, error) {
|
|
return nil, nil
|
|
}
|
|
func (d *spider91UploadTargetFakeDrive) Stat(context.Context, string) (*drives.Entry, error) {
|
|
return nil, drives.ErrNotSupported
|
|
}
|
|
func (d *spider91UploadTargetFakeDrive) StreamURL(context.Context, string) (*drives.StreamLink, error) {
|
|
return nil, drives.ErrNotSupported
|
|
}
|
|
func (d *spider91UploadTargetFakeDrive) Upload(context.Context, string, string, io.Reader, int64) (string, error) {
|
|
return "", drives.ErrNotSupported
|
|
}
|
|
func (d *spider91UploadTargetFakeDrive) EnsureDir(context.Context, string) (string, error) {
|
|
return "", drives.ErrNotSupported
|
|
}
|
|
func (d *spider91UploadTargetFakeDrive) RootID() string { return "root" }
|