Skip to content

Commit

Permalink
feat(offline_download): add simple http tool (close #4002)
Browse files Browse the repository at this point in the history
  • Loading branch information
xhofe committed Nov 24, 2023
1 parent b6134dc commit 34746e9
Show file tree
Hide file tree
Showing 8 changed files with 131 additions and 0 deletions.
4 changes: 4 additions & 0 deletions internal/errs/errors.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,3 +29,7 @@ func NewErr(err error, format string, a ...any) error {
func IsNotFoundError(err error) bool {
return errors.Is(pkgerr.Cause(err), ObjectNotFound) || errors.Is(pkgerr.Cause(err), StorageNotFound)
}

func IsNotSupportError(err error) bool {
return errors.Is(pkgerr.Cause(err), NotSupport)
}
1 change: 1 addition & 0 deletions internal/offline_download/all.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,5 +2,6 @@ package offline_download

import (
_ "github.com/alist-org/alist/v3/internal/offline_download/aria2"
_ "github.com/alist-org/alist/v3/internal/offline_download/http"
_ "github.com/alist-org/alist/v3/internal/offline_download/qbit"
)
5 changes: 5 additions & 0 deletions internal/offline_download/aria2/aria2.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package aria2
import (
"context"
"fmt"
"github.com/alist-org/alist/v3/internal/errs"
"strconv"
"time"

Expand All @@ -21,6 +22,10 @@ type Aria2 struct {
client rpc.Client
}

func (a *Aria2) Run(task *tool.DownloadTask) error {
return errs.NotSupport
}

func (a *Aria2) Name() string {
return "aria2"
}
Expand Down
85 changes: 85 additions & 0 deletions internal/offline_download/http/client.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
package http

import (
"fmt"
"github.com/alist-org/alist/v3/internal/model"
"github.com/alist-org/alist/v3/internal/offline_download/tool"
"github.com/alist-org/alist/v3/pkg/utils"
"net/http"
"net/url"
"os"
"path"
"path/filepath"
)

type SimpleHttp struct {
client http.Client
}

func (s SimpleHttp) Name() string {
return "SimpleHttp"
}

func (s SimpleHttp) Items() []model.SettingItem {
return nil
}

func (s SimpleHttp) Init() (string, error) {
return "ok", nil
}

func (s SimpleHttp) IsReady() bool {
return true
}

func (s SimpleHttp) AddURL(args *tool.AddUrlArgs) (string, error) {
panic("should not be called")
}

func (s SimpleHttp) Remove(task *tool.DownloadTask) error {
panic("should not be called")
}

func (s SimpleHttp) Status(task *tool.DownloadTask) (*tool.Status, error) {
panic("should not be called")
}

func (s SimpleHttp) Run(task *tool.DownloadTask) error {
u := task.Url
// parse url
_u, err := url.Parse(u)
if err != nil {
return err
}
req, err := http.NewRequestWithContext(task.Ctx(), http.MethodGet, u, nil)
if err != nil {
return err
}
resp, err := s.client.Do(req)
if err != nil {
return err
}
defer resp.Body.Close()
if resp.StatusCode >= 400 {
return fmt.Errorf("http status code %d", resp.StatusCode)
}
filename := path.Base(_u.Path)
if n, err := parseFilenameFromContentDisposition(resp.Header.Get("Content-Disposition")); err == nil {
filename = n
}
// save to temp dir
_ = os.MkdirAll(task.TempDir, os.ModePerm)
filePath := filepath.Join(task.TempDir, filename)
file, err := os.Create(filePath)
if err != nil {
return err
}
defer file.Close()
fileSize := resp.ContentLength
err = utils.CopyWithCtx(task.Ctx(), file, resp.Body, fileSize, task.SetProgress)
return err
}

func init() {
tool.Tools.Add(&SimpleHttp{})
}
21 changes: 21 additions & 0 deletions internal/offline_download/http/util.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
package http

import (
"fmt"
"mime"
)

func parseFilenameFromContentDisposition(contentDisposition string) (string, error) {
if contentDisposition == "" {
return "", fmt.Errorf("Content-Disposition is empty")
}
_, params, err := mime.ParseMediaType(contentDisposition)
if err != nil {
return "", err
}
filename := params["filename"]
if filename == "" {
return "", fmt.Errorf("filename not found in Content-Disposition: [%s]", contentDisposition)
}
return filename, nil
}
5 changes: 5 additions & 0 deletions internal/offline_download/qbit/qbit.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package qbit

import (
"github.com/alist-org/alist/v3/internal/conf"
"github.com/alist-org/alist/v3/internal/errs"
"github.com/alist-org/alist/v3/internal/model"
"github.com/alist-org/alist/v3/internal/offline_download/tool"
"github.com/alist-org/alist/v3/internal/setting"
Expand All @@ -13,6 +14,10 @@ type QBittorrent struct {
client qbittorrent.Client
}

func (a *QBittorrent) Run(task *tool.DownloadTask) error {
return errs.NotSupport
}

func (a *QBittorrent) Name() string {
return "qBittorrent"
}
Expand Down
3 changes: 3 additions & 0 deletions internal/offline_download/tool/base.go
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,9 @@ type Tool interface {
Remove(task *DownloadTask) error
// Status return the status of the download task, if an error occurred, return the error in Status.Err
Status(task *DownloadTask) (*Status, error)

// Run for simple http download
Run(task *DownloadTask) error
}

type GetFileser interface {
Expand Down
7 changes: 7 additions & 0 deletions internal/offline_download/tool/download.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package tool

import (
"fmt"
"github.com/alist-org/alist/v3/internal/errs"
"github.com/pkg/errors"
log "github.com/sirupsen/logrus"
"github.com/xhofe/tache"
Expand All @@ -25,6 +26,12 @@ type DownloadTask struct {
}

func (t *DownloadTask) Run() error {
if err := t.tool.Run(t); !errs.IsNotSupportError(err) {
if err == nil {
return t.Complete()
}
return err
}
t.Signal = make(chan int)
t.finish = make(chan struct{})
defer func() {
Expand Down

0 comments on commit 34746e9

Please sign in to comment.