Skip to content

Commit

Permalink
feat: support qbittorrent (close AlistGo#3087 in AlistGo#3333)
Browse files Browse the repository at this point in the history
* feat(qbittorrent): authorization and logging in support

* feat(qbittorrent/client): support `AddFromLink`

* refactor(qbittorrent/client): check authorization when getting a new client

* feat(qbittorrent/client): support `GetInfo`

* test(qbittorrent/client): update test cases

* feat(qbittorrent): init qbittorrent client on bootstrap

* feat(qbittorrent): support setting webui url via gin

* feat(qbittorrent/client): support deleting

* feat(qbittorrent/client): parse `TorrentStatus` enum when unmarshalling json in `GetInfo()`

* feat(qbittorrent/client): support getting files by id

* feat(qbittorrent): support adding qbittorrent tasks via gin

* refactor(qbittorrent/client): return a `Client` interface in `New()` instead of `*client`

* refactor: task handle

* chore: fix typo

* chore: change path

---------

Co-authored-by: Andy Hsu <[email protected]>
  • Loading branch information
2 people authored and walleoo committed Feb 26, 2023
1 parent 73ea8c7 commit 7a12d07
Show file tree
Hide file tree
Showing 14 changed files with 932 additions and 239 deletions.
1 change: 1 addition & 0 deletions cmd/server.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ the address is defined in config file`,
Run: func(cmd *cobra.Command, args []string) {
Init()
bootstrap.InitAria2()
bootstrap.InitQbittorrent()
bootstrap.LoadStorages()
if !flags.Debug && !flags.Dev {
gin.SetMode(gin.ReleaseMode)
Expand Down
3 changes: 3 additions & 0 deletions internal/bootstrap/data/setting.go
Original file line number Diff line number Diff line change
Expand Up @@ -154,6 +154,9 @@ func InitialSettings() []model.SettingItem {
{Key: conf.GithubClientId, Value: "", Type: conf.TypeString, Group: model.GITHUB, Flag: model.PRIVATE},
{Key: conf.GithubClientSecrets, Value: "", Type: conf.TypeString, Group: model.GITHUB, Flag: model.PRIVATE},
{Key: conf.GithubLoginEnabled, Value: "false", Type: conf.TypeBool, Group: model.GITHUB, Flag: model.PUBLIC},

// qbittorrent settings
{Key: conf.QbittorrentUrl, Value: "http://admin:adminadmin@localhost:8080/", Type: conf.TypeString, Group: model.QBITTORRENT, Flag: model.PRIVATE},
}
if flags.Dev {
initialSettingItems = append(initialSettingItems, []model.SettingItem{
Expand Down
15 changes: 15 additions & 0 deletions internal/bootstrap/qbittorrent.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
package bootstrap

import (
"github.com/alist-org/alist/v3/internal/qbittorrent"
"github.com/alist-org/alist/v3/pkg/utils"
)

func InitQbittorrent() {
go func() {
err := qbittorrent.InitClient()
if err != nil {
utils.Log.Infof("qbittorrent not ready.")
}
}()
}
81 changes: 42 additions & 39 deletions internal/conf/const.go
Original file line number Diff line number Diff line change
@@ -1,33 +1,33 @@
package conf

const (
TypeString = "string"
TypeSelect = "select"
TypeBool = "bool"
TypeText = "text"
TypeNumber = "number"
TypeString = "string"
TypeSelect = "select"
TypeBool = "bool"
TypeText = "text"
TypeNumber = "number"
)

const (
// site
VERSION = "version"
SiteTitle = "site_title"
Announcement = "announcement"
AllowIndexed = "allow_indexed"
// site
VERSION = "version"
SiteTitle = "site_title"
Announcement = "announcement"
AllowIndexed = "allow_indexed"

Logo = "logo"
Favicon = "favicon"
MainColor = "main_color"
Logo = "logo"
Favicon = "favicon"
MainColor = "main_color"

// preview
TextTypes = "text_types"
AudioTypes = "audio_types"
VideoTypes = "video_types"
ImageTypes = "image_types"
ProxyTypes = "proxy_types"
ProxyIgnoreHeaders = "proxy_ignore_headers"
AudioAutoplay = "audio_autoplay"
VideoAutoplay = "video_autoplay"
// preview
TextTypes = "text_types"
AudioTypes = "audio_types"
VideoTypes = "video_types"
ImageTypes = "image_types"
ProxyTypes = "proxy_types"
ProxyIgnoreHeaders = "proxy_ignore_headers"
AudioAutoplay = "audio_autoplay"
VideoAutoplay = "video_autoplay"

// global
HideFiles = "hide_files"
Expand All @@ -46,26 +46,29 @@ const (
IgnorePaths = "ignore_paths"
MaxIndexDepth = "max_index_depth"

// aria2
Aria2Uri = "aria2_uri"
Aria2Secret = "aria2_secret"
// aria2
Aria2Uri = "aria2_uri"
Aria2Secret = "aria2_secret"

// single
Token = "token"
IndexProgress = "index_progress"
// single
Token = "token"
IndexProgress = "index_progress"

//Github
GithubClientId = "github_client_id"
GithubClientSecrets = "github_client_secrets"
GithubLoginEnabled = "github_login_enabled"
//Github
GithubClientId = "github_client_id"
GithubClientSecrets = "github_client_secrets"
GithubLoginEnabled = "github_login_enabled"

// qbittorrent
QbittorrentUrl = "qbittorrent_url"
)

const (
UNKNOWN = iota
FOLDER
//OFFICE
VIDEO
AUDIO
TEXT
IMAGE
UNKNOWN = iota
FOLDER
//OFFICE
VIDEO
AUDIO
TEXT
IMAGE
)
1 change: 1 addition & 0 deletions internal/model/setting.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ const (
ARIA2
INDEX
GITHUB
QBITTORRENT
)

const (
Expand Down
25 changes: 15 additions & 10 deletions internal/model/user.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,16 +20,17 @@ type User struct {
Role int `json:"role"` // user's role
Disabled bool `json:"disabled"`
// Determine permissions by bit
// 0: can see hidden files
// 1: can access without password
// 2: can add aria2 tasks
// 3: can mkdir and upload
// 4: can rename
// 5: can move
// 6: can copy
// 7: can remove
// 8: webdav read
// 9: webdav write
// 0: can see hidden files
// 1: can access without password
// 2: can add aria2 tasks
// 3: can mkdir and upload
// 4: can rename
// 5: can move
// 6: can copy
// 7: can remove
// 8: webdav read
// 9: webdav write
// 10: can add qbittorrent tasks
Permission int32 `json:"permission"`
OtpSecret string `json:"-"`
GithubID int `json:"github_id"`
Expand Down Expand Up @@ -93,6 +94,10 @@ func (u User) CanWebdavManage() bool {
return u.IsAdmin() || (u.Permission>>9)&1 == 1
}

func (u User) CanAddQbittorrentTasks() bool {
return u.IsAdmin() || (u.Permission>>10)&1 == 1
}

func (u User) JoinPath(reqPath string) (string, error) {
return utils.JoinBasePath(u.BasePath, reqPath)
}
58 changes: 58 additions & 0 deletions internal/qbittorrent/add.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
package qbittorrent

import (
"context"
"fmt"
"path/filepath"

"github.com/alist-org/alist/v3/internal/conf"
"github.com/alist-org/alist/v3/internal/errs"
"github.com/alist-org/alist/v3/internal/op"
"github.com/alist-org/alist/v3/pkg/task"
"github.com/google/uuid"
"github.com/pkg/errors"
)

func AddURL(ctx context.Context, url string, dstDirPath string) error {
// check storage
storage, dstDirActualPath, err := op.GetStorageAndActualPath(dstDirPath)
if err != nil {
return errors.WithMessage(err, "failed get storage")
}
// check is it could upload
if storage.Config().NoUpload {
return errors.WithStack(errs.UploadNotSupported)
}
// check path is valid
obj, err := op.Get(ctx, storage, dstDirActualPath)
if err != nil {
if !errs.IsObjectNotFound(err) {
return errors.WithMessage(err, "failed get object")
}
} else {
if !obj.IsDir() {
// can't add to a file
return errors.WithStack(errs.NotFolder)
}
}
// call qbittorrent
id := uuid.NewString()
tempDir := filepath.Join(conf.Conf.TempDir, "qbittorrent", id)
err = qbclient.AddFromLink(url, tempDir, id)
if err != nil {
return errors.Wrapf(err, "failed to add url %s", url)
}
DownTaskManager.Submit(task.WithCancelCtx(&task.Task[string]{
ID: id,
Name: fmt.Sprintf("download %s to [%s](%s)", url, storage.GetStorage().MountPath, dstDirActualPath),
Func: func(tsk *task.Task[string]) error {
m := &Monitor{
tsk: tsk,
tempDir: tempDir,
dstDirPath: dstDirPath,
}
return m.Loop()
},
}))
return nil
}
Loading

0 comments on commit 7a12d07

Please sign in to comment.