Skip to content

Commit 34746e9

Browse files
committed
feat(offline_download): add simple http tool (close #4002)
1 parent b6134dc commit 34746e9

8 files changed

Lines changed: 131 additions & 0 deletions

File tree

internal/errs/errors.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,3 +29,7 @@ func NewErr(err error, format string, a ...any) error {
2929
func IsNotFoundError(err error) bool {
3030
return errors.Is(pkgerr.Cause(err), ObjectNotFound) || errors.Is(pkgerr.Cause(err), StorageNotFound)
3131
}
32+
33+
func IsNotSupportError(err error) bool {
34+
return errors.Is(pkgerr.Cause(err), NotSupport)
35+
}

internal/offline_download/all.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,5 +2,6 @@ package offline_download
22

33
import (
44
_ "github.com/alist-org/alist/v3/internal/offline_download/aria2"
5+
_ "github.com/alist-org/alist/v3/internal/offline_download/http"
56
_ "github.com/alist-org/alist/v3/internal/offline_download/qbit"
67
)

internal/offline_download/aria2/aria2.go

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ package aria2
33
import (
44
"context"
55
"fmt"
6+
"github.com/alist-org/alist/v3/internal/errs"
67
"strconv"
78
"time"
89

@@ -21,6 +22,10 @@ type Aria2 struct {
2122
client rpc.Client
2223
}
2324

25+
func (a *Aria2) Run(task *tool.DownloadTask) error {
26+
return errs.NotSupport
27+
}
28+
2429
func (a *Aria2) Name() string {
2530
return "aria2"
2631
}
Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,85 @@
1+
package http
2+
3+
import (
4+
"fmt"
5+
"github.com/alist-org/alist/v3/internal/model"
6+
"github.com/alist-org/alist/v3/internal/offline_download/tool"
7+
"github.com/alist-org/alist/v3/pkg/utils"
8+
"net/http"
9+
"net/url"
10+
"os"
11+
"path"
12+
"path/filepath"
13+
)
14+
15+
type SimpleHttp struct {
16+
client http.Client
17+
}
18+
19+
func (s SimpleHttp) Name() string {
20+
return "SimpleHttp"
21+
}
22+
23+
func (s SimpleHttp) Items() []model.SettingItem {
24+
return nil
25+
}
26+
27+
func (s SimpleHttp) Init() (string, error) {
28+
return "ok", nil
29+
}
30+
31+
func (s SimpleHttp) IsReady() bool {
32+
return true
33+
}
34+
35+
func (s SimpleHttp) AddURL(args *tool.AddUrlArgs) (string, error) {
36+
panic("should not be called")
37+
}
38+
39+
func (s SimpleHttp) Remove(task *tool.DownloadTask) error {
40+
panic("should not be called")
41+
}
42+
43+
func (s SimpleHttp) Status(task *tool.DownloadTask) (*tool.Status, error) {
44+
panic("should not be called")
45+
}
46+
47+
func (s SimpleHttp) Run(task *tool.DownloadTask) error {
48+
u := task.Url
49+
// parse url
50+
_u, err := url.Parse(u)
51+
if err != nil {
52+
return err
53+
}
54+
req, err := http.NewRequestWithContext(task.Ctx(), http.MethodGet, u, nil)
55+
if err != nil {
56+
return err
57+
}
58+
resp, err := s.client.Do(req)
59+
if err != nil {
60+
return err
61+
}
62+
defer resp.Body.Close()
63+
if resp.StatusCode >= 400 {
64+
return fmt.Errorf("http status code %d", resp.StatusCode)
65+
}
66+
filename := path.Base(_u.Path)
67+
if n, err := parseFilenameFromContentDisposition(resp.Header.Get("Content-Disposition")); err == nil {
68+
filename = n
69+
}
70+
// save to temp dir
71+
_ = os.MkdirAll(task.TempDir, os.ModePerm)
72+
filePath := filepath.Join(task.TempDir, filename)
73+
file, err := os.Create(filePath)
74+
if err != nil {
75+
return err
76+
}
77+
defer file.Close()
78+
fileSize := resp.ContentLength
79+
err = utils.CopyWithCtx(task.Ctx(), file, resp.Body, fileSize, task.SetProgress)
80+
return err
81+
}
82+
83+
func init() {
84+
tool.Tools.Add(&SimpleHttp{})
85+
}
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
package http
2+
3+
import (
4+
"fmt"
5+
"mime"
6+
)
7+
8+
func parseFilenameFromContentDisposition(contentDisposition string) (string, error) {
9+
if contentDisposition == "" {
10+
return "", fmt.Errorf("Content-Disposition is empty")
11+
}
12+
_, params, err := mime.ParseMediaType(contentDisposition)
13+
if err != nil {
14+
return "", err
15+
}
16+
filename := params["filename"]
17+
if filename == "" {
18+
return "", fmt.Errorf("filename not found in Content-Disposition: [%s]", contentDisposition)
19+
}
20+
return filename, nil
21+
}

internal/offline_download/qbit/qbit.go

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ package qbit
22

33
import (
44
"github.com/alist-org/alist/v3/internal/conf"
5+
"github.com/alist-org/alist/v3/internal/errs"
56
"github.com/alist-org/alist/v3/internal/model"
67
"github.com/alist-org/alist/v3/internal/offline_download/tool"
78
"github.com/alist-org/alist/v3/internal/setting"
@@ -13,6 +14,10 @@ type QBittorrent struct {
1314
client qbittorrent.Client
1415
}
1516

17+
func (a *QBittorrent) Run(task *tool.DownloadTask) error {
18+
return errs.NotSupport
19+
}
20+
1621
func (a *QBittorrent) Name() string {
1722
return "qBittorrent"
1823
}

internal/offline_download/tool/base.go

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,9 @@ type Tool interface {
3535
Remove(task *DownloadTask) error
3636
// Status return the status of the download task, if an error occurred, return the error in Status.Err
3737
Status(task *DownloadTask) (*Status, error)
38+
39+
// Run for simple http download
40+
Run(task *DownloadTask) error
3841
}
3942

4043
type GetFileser interface {

internal/offline_download/tool/download.go

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ package tool
22

33
import (
44
"fmt"
5+
"github.com/alist-org/alist/v3/internal/errs"
56
"github.com/pkg/errors"
67
log "github.com/sirupsen/logrus"
78
"github.com/xhofe/tache"
@@ -25,6 +26,12 @@ type DownloadTask struct {
2526
}
2627

2728
func (t *DownloadTask) Run() error {
29+
if err := t.tool.Run(t); !errs.IsNotSupportError(err) {
30+
if err == nil {
31+
return t.Complete()
32+
}
33+
return err
34+
}
2835
t.Signal = make(chan int)
2936
t.finish = make(chan struct{})
3037
defer func() {

0 commit comments

Comments
 (0)