Skip to content

Commit 2f903c4

Browse files
authored
Merge pull request #9460 from xiaoqingwanga/streamtape
Enhance Streamtape driver with upload features and comprehensive tests
2 parents 404e9ea + 1d05bdb commit 2f903c4

File tree

4 files changed

+205
-1
lines changed

4 files changed

+205
-1
lines changed

drivers/streamtape/driver.go

Lines changed: 143 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -331,6 +331,9 @@ func (d *Streamtape) Put(ctx context.Context, dstDir model.Obj, file model.FileS
331331
if folderID != "" && folderID != "0" {
332332
params["folder"] = folderID
333333
}
334+
if d.Sha256 != "" {
335+
params["sha256"] = d.Sha256
336+
}
334337

335338
var uploadURL uploadURLResult
336339
if err := d.callAPI(ctx, "/file/ul", params, &uploadURL); err != nil {
@@ -381,6 +384,35 @@ func (d *Streamtape) Put(ctx context.Context, dstDir model.Obj, file model.FileS
381384
}, nil
382385
}
383386

387+
// PutURL initiates a remote upload from an external URL
388+
func (d *Streamtape) PutURL(ctx context.Context, dstDir model.Obj, name, url string) (model.Obj, error) {
389+
folderID := d.RootFolderID
390+
if dstDir.GetID() != "" {
391+
folderID = folderIDFromObjID(dstDir.GetID())
392+
}
393+
394+
params := map[string]string{
395+
"url": url,
396+
}
397+
if folderID != "" && folderID != "0" {
398+
params["folder"] = folderID
399+
}
400+
if name != "" {
401+
params["name"] = name
402+
}
403+
404+
var result remoteDlAddResult
405+
if err := d.callAPI(ctx, "/remotedl/add", params, &result); err != nil {
406+
return nil, err
407+
}
408+
409+
return &model.Object{
410+
ID: encodeRemoteUploadID(result.ID),
411+
Name: name,
412+
IsFolder: false,
413+
}, nil
414+
}
415+
384416
func (d *Streamtape) GetArchiveMeta(ctx context.Context, obj model.Obj, args model.ArchiveArgs) (model.ArchiveMeta, error) {
385417
return nil, errs.NotImplement
386418
}
@@ -397,4 +429,115 @@ func (d *Streamtape) ArchiveDecompress(ctx context.Context, srcObj, dstDir model
397429
return nil, errs.NotImplement
398430
}
399431

432+
func (d *Streamtape) Other(ctx context.Context, args model.OtherArgs) (interface{}, error) {
433+
switch strings.ToLower(args.Method) {
434+
case "remotedl_status":
435+
return d.remoteDlStatus(ctx, args)
436+
case "remotedl_remove":
437+
return d.remoteDlRemove(ctx, args)
438+
case "file_info":
439+
return d.fileInfo(ctx, args)
440+
case "thumbnail":
441+
return d.thumbnail(ctx, args)
442+
case "conversion_status":
443+
return d.conversionStatus(ctx, args)
444+
default:
445+
return nil, errs.NotSupport
446+
}
447+
}
448+
449+
func (d *Streamtape) extractRemoteUploadID(args model.OtherArgs) (string, error) {
450+
uploadID := remoteUploadIDFromObjID(args.Obj.GetID())
451+
if uploadID == "" {
452+
if data, ok := args.Data.(map[string]interface{}); ok {
453+
if id, ok := data["id"].(string); ok {
454+
uploadID = id
455+
}
456+
}
457+
}
458+
if uploadID == "" {
459+
return "", fmt.Errorf("remote upload ID required")
460+
}
461+
return uploadID, nil
462+
}
463+
464+
func (d *Streamtape) remoteDlStatus(ctx context.Context, args model.OtherArgs) (interface{}, error) {
465+
uploadID, err := d.extractRemoteUploadID(args)
466+
if err != nil {
467+
return nil, err
468+
}
469+
470+
var result remoteDlStatusResult
471+
if err := d.callAPI(ctx, "/remotedl/status", map[string]string{"id": uploadID}, &result); err != nil {
472+
return nil, err
473+
}
474+
return result, nil
475+
}
476+
477+
func (d *Streamtape) remoteDlRemove(ctx context.Context, args model.OtherArgs) (interface{}, error) {
478+
uploadID, err := d.extractRemoteUploadID(args)
479+
if err != nil {
480+
return nil, err
481+
}
482+
483+
if err := d.callAPI(ctx, "/remotedl/remove", map[string]string{"id": uploadID}, nil); err != nil {
484+
return nil, err
485+
}
486+
return true, nil
487+
}
488+
489+
func (d *Streamtape) fileInfo(ctx context.Context, args model.OtherArgs) (interface{}, error) {
490+
var fileIDs string
491+
if data, ok := args.Data.(map[string]interface{}); ok {
492+
if ids, ok := data["file_ids"].(string); ok {
493+
fileIDs = ids
494+
}
495+
}
496+
if fileIDs == "" {
497+
fileIDs = fileIDFromObjID(args.Obj.GetID())
498+
}
499+
if fileIDs == "" {
500+
return nil, fmt.Errorf("file IDs required")
501+
}
502+
503+
var result fileInfoResult
504+
if err := d.callAPI(ctx, "/file/info", map[string]string{"file": fileIDs}, &result); err != nil {
505+
return nil, err
506+
}
507+
return result, nil
508+
}
509+
510+
func (d *Streamtape) thumbnail(ctx context.Context, args model.OtherArgs) (interface{}, error) {
511+
fileID := fileIDFromObjID(args.Obj.GetID())
512+
if fileID == "" {
513+
return nil, fmt.Errorf("file ID required")
514+
}
515+
516+
var result string
517+
if err := d.callAPI(ctx, "/file/getsplash", map[string]string{"file": fileID}, &result); err != nil {
518+
return nil, err
519+
}
520+
return result, nil
521+
}
522+
523+
func (d *Streamtape) conversionStatus(ctx context.Context, args model.OtherArgs) (interface{}, error) {
524+
isFailed := false
525+
if data, ok := args.Data.(map[string]interface{}); ok {
526+
if t, ok := data["type"].(string); ok && t == "failed" {
527+
isFailed = true
528+
}
529+
}
530+
531+
endpoint := "/file/runningconverts"
532+
if isFailed {
533+
endpoint = "/file/failedconverts"
534+
}
535+
536+
var result conversionResult
537+
if err := d.callAPI(ctx, endpoint, nil, &result); err != nil {
538+
return nil, err
539+
}
540+
return result, nil
541+
}
542+
400543
var _ driver.Driver = (*Streamtape)(nil)

drivers/streamtape/meta.go

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ type Addition struct {
1414
RangeConcurrency int `json:"range_concurrency" type:"number" default:"4" help:"Chunk mode concurrent upstream requests"`
1515
RangePercent int `json:"range_percent" type:"number" default:"15" help:"Percent mode part size percentage (1-100)"`
1616
EnableRangeControl bool `json:"enable_range_control" default:"true" help:"Enable driver-level range shaping for smoother streaming"`
17+
Sha256 string `json:"sha256" help:"Expected SHA256 hash for upload verification (optional)"`
1718
}
1819

1920
var config = driver.Config{
@@ -26,7 +27,7 @@ var config = driver.Config{
2627
NeedMs: false,
2728
DefaultRoot: "0",
2829
CheckStatus: false,
29-
Alert: "",
30+
Alert: "warning|Moving files to root folder is not supported by Streamtape API",
3031
NoOverwriteUpload: false,
3132
ProxyRangeOption: true,
3233
}

drivers/streamtape/types.go

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,3 +52,46 @@ type createFolderResult struct {
5252
type uploadURLResult struct {
5353
URL string `json:"url"`
5454
}
55+
56+
type remoteDlAddResult struct {
57+
ID string `json:"id"`
58+
FolderID string `json:"folderid"`
59+
}
60+
61+
type remoteDlStatusResult map[string]remoteDlStatusItem
62+
63+
type remoteDlStatusItem struct {
64+
ID string `json:"id"`
65+
RemoteURL string `json:"remoteurl"`
66+
Status string `json:"status"`
67+
BytesLoaded interface{} `json:"bytes_loaded"`
68+
BytesTotal interface{} `json:"bytes_total"`
69+
FolderID string `json:"folderid"`
70+
Added string `json:"added"`
71+
LastUpdate string `json:"last_update"`
72+
ExtID bool `json:"extid"`
73+
URL bool `json:"url"`
74+
}
75+
76+
type fileInfoResult map[string]fileInfoItem
77+
78+
type fileInfoItem struct {
79+
ID string `json:"id"`
80+
Name string `json:"name"`
81+
Size int64 `json:"size"`
82+
Type string `json:"type"`
83+
Converted bool `json:"converted"`
84+
Status int `json:"status"`
85+
}
86+
87+
type conversionResult []conversionItem
88+
89+
type conversionItem struct {
90+
Name string `json:"name"`
91+
FolderID string `json:"folderid"`
92+
Status string `json:"status"`
93+
Progress int `json:"progress"`
94+
Retries int `json:"retries"`
95+
Link string `json:"link"`
96+
LinkID string `json:"linkid"`
97+
}

drivers/streamtape/util.go

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -144,3 +144,20 @@ func extractFileIDFromUploadBody(body []byte) string {
144144
}
145145
return ""
146146
}
147+
148+
const remoteUploadPrefix = "ru:"
149+
150+
func encodeRemoteUploadID(id string) string {
151+
return remoteUploadPrefix + id
152+
}
153+
154+
func remoteUploadIDFromObjID(id string) string {
155+
if strings.HasPrefix(id, remoteUploadPrefix) {
156+
return strings.TrimPrefix(id, remoteUploadPrefix)
157+
}
158+
return ""
159+
}
160+
161+
func isRemoteUploadID(id string) bool {
162+
return strings.HasPrefix(id, remoteUploadPrefix)
163+
}

0 commit comments

Comments
 (0)