359 lines
12 KiB
Go
359 lines
12 KiB
Go
package qbittorrent
|
|
|
|
import (
|
|
"context"
|
|
"encoding/json"
|
|
"errors"
|
|
"fmt"
|
|
"net/http"
|
|
"net/url"
|
|
"strings"
|
|
)
|
|
|
|
type RSS interface {
|
|
// AddFolder create new folder for rss, full path of added folder such as "The Pirate Bay\Top100"
|
|
AddFolder(ctx context.Context, path string) error
|
|
// AddFeed add feed
|
|
AddFeed(ctx context.Context, option *RssAddFeedOption) error
|
|
// RemoveItem remove folder or feed
|
|
RemoveItem(ctx context.Context, path string) error
|
|
// MoveItem move or rename folder or feed
|
|
MoveItem(ctx context.Context, srcPath, destPath string) error
|
|
// GetItems list all items, if withData is true, will return all data
|
|
GetItems(ctx context.Context, withData bool) (map[string]interface{}, error)
|
|
// MarkAsRead if articleId is provided only the article is marked as read otherwise the whole feed
|
|
// is going to be marked as read.
|
|
MarkAsRead(ctx context.Context, option *RssMarkAsReadOption) error
|
|
// RefreshItem refresh folder or feed
|
|
RefreshItem(ctx context.Context, itemPath string) error
|
|
// SetAutoDownloadingRule set auto-downloading rule
|
|
SetAutoDownloadingRule(ctx context.Context, ruleName string, ruleDef *RssAutoDownloadingRuleDef) error
|
|
// RenameAutoDownloadingRule rename auto-downloading rule
|
|
RenameAutoDownloadingRule(ctx context.Context, ruleName, newRuleName string) error
|
|
// RemoveAutoDownloadingRule remove auto-downloading rule
|
|
RemoveAutoDownloadingRule(ctx context.Context, ruleName string) error
|
|
// GetAllAutoDownloadingRules get all auto-downloading rules
|
|
GetAllAutoDownloadingRules(ctx context.Context) (map[string]*RssAutoDownloadingRuleDef, error)
|
|
// GetAllArticlesMatchingRule get all articles matching a rule
|
|
GetAllArticlesMatchingRule(ctx context.Context, ruleName string) (map[string][]string, error)
|
|
}
|
|
|
|
type RssAddFeedOption struct {
|
|
// URL feed of rss such as http://thepiratebay.org/rss//top100/200
|
|
URL string `schema:"url"`
|
|
// Folder full path of added folder, optional
|
|
Folder string `schema:"path,omitempty"`
|
|
}
|
|
|
|
type RssMarkAsReadOption struct {
|
|
// ItemPath current full path of item
|
|
ItemPath string `schema:"itemPath"`
|
|
// ArticleId id of article, optional
|
|
ArticleId string `schema:"articleId,omitempty"`
|
|
}
|
|
|
|
type RssAutoDownloadingRuleDefTorrentParams struct {
|
|
Category string `json:"category,omitempty"`
|
|
DownloadLimit int `json:"download_limit,omitempty"`
|
|
DownloadPath int `json:"download_path,omitempty"`
|
|
InactiveSeedingTimeLimit int `json:"inactive_seeding_time_limit,omitempty"`
|
|
OperatingMode string `json:"operating_mode,omitempty"`
|
|
RatioLimit int `json:"ratio_limit,omitempty"`
|
|
SavePath string `json:"save_path,omitempty"`
|
|
SeedingTimeLimit int `json:"seeding_time_limit,omitempty"`
|
|
SkipChecking bool `json:"skip_checking,omitempty"`
|
|
Tags []string `json:"tags,omitempty"`
|
|
UploadLimit int `json:"upload_limit,omitempty"`
|
|
Stopped bool `json:"stopped,omitempty"`
|
|
UseAutoTMM bool `json:"use_auto_tmm,omitempty"`
|
|
}
|
|
|
|
type RssAutoDownloadingRuleDef struct {
|
|
AddPaused bool `json:"addPaused,omitempty"`
|
|
AffectedFeeds []string `json:"affectedFeeds,omitempty"`
|
|
AssignedCategory string `json:"assignedCategory,omitempty"`
|
|
Enabled bool `json:"enabled,omitempty"`
|
|
EpisodeFilter string `json:"episodeFilter,omitempty"`
|
|
IgnoreDays int `json:"ignoreDays,omitempty"`
|
|
LastMatch string `json:"lastMatch,omitempty"`
|
|
MustContain string `json:"mustContain,omitempty"`
|
|
MustNotContain string `json:"mustNotContain,omitempty"`
|
|
PreviouslyMatchedEpisodes []string `json:"previouslyMatchedEpisodes,omitempty"`
|
|
Priority int `json:"priority,omitempty"`
|
|
SavePath string `json:"savePath,omitempty"`
|
|
SmartFilter bool `json:"smartFilter,omitempty"`
|
|
TorrentParams *RssAutoDownloadingRuleDefTorrentParams `json:"torrentParams,omitempty"`
|
|
UseRegex bool `json:"useRegex,omitempty"`
|
|
}
|
|
|
|
func (c *client) AddFolder(ctx context.Context, path string) error {
|
|
ctx, span := trace.Start(ctx, "qbittorrent.RSS.AddFolder")
|
|
defer span.End()
|
|
|
|
var formData = url.Values{}
|
|
formData.Add("path", path)
|
|
var apiUrl = fmt.Sprintf("%s/api/v2/rss/addFolder", c.config.Address)
|
|
result, err := c.doRequest(ctx, &requestData{
|
|
url: apiUrl,
|
|
method: http.MethodPost,
|
|
body: strings.NewReader(formData.Encode()),
|
|
})
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
if result.code != 200 {
|
|
return errors.New("add rss folder failed: " + string(result.body))
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func (c *client) AddFeed(ctx context.Context, opt *RssAddFeedOption) error {
|
|
ctx, span := trace.Start(ctx, "qbittorrent.RSS.AddFeed")
|
|
defer span.End()
|
|
|
|
var formData = url.Values{}
|
|
err := encoder.Encode(opt, formData)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
var apiUrl = fmt.Sprintf("%s/api/v2/rss/addFolder", c.config.Address)
|
|
result, err := c.doRequest(ctx, &requestData{
|
|
url: apiUrl,
|
|
method: http.MethodPost,
|
|
body: strings.NewReader(formData.Encode()),
|
|
})
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
if result.code != 200 {
|
|
return errors.New("add rss feed failed: " + string(result.body))
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func (c *client) RemoveItem(ctx context.Context, path string) error {
|
|
ctx, span := trace.Start(ctx, "qbittorrent.RSS.RemoveItem")
|
|
defer span.End()
|
|
|
|
var formData = url.Values{}
|
|
formData.Add("path", path)
|
|
var apiUrl = fmt.Sprintf("%s/api/v2/rss/removeItem", c.config.Address)
|
|
result, err := c.doRequest(ctx, &requestData{
|
|
url: apiUrl,
|
|
method: http.MethodPost,
|
|
body: strings.NewReader(formData.Encode()),
|
|
})
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
if result.code != 200 {
|
|
return errors.New("remove rss item failed: " + string(result.body))
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func (c *client) MoveItem(ctx context.Context, srcPath, destPath string) error {
|
|
ctx, span := trace.Start(ctx, "qbittorrent.RSS.MoveItem")
|
|
defer span.End()
|
|
|
|
var formData = url.Values{}
|
|
formData.Add("itemPath", srcPath)
|
|
formData.Add("destPath", destPath)
|
|
var apiUrl = fmt.Sprintf("%s/api/v2/rss/moveItem", c.config.Address)
|
|
result, err := c.doRequest(ctx, &requestData{
|
|
url: apiUrl,
|
|
method: http.MethodPost,
|
|
body: strings.NewReader(formData.Encode()),
|
|
})
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
if result.code != 200 {
|
|
return errors.New("move rss item failed: " + string(result.body))
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func (c *client) GetItems(ctx context.Context, withData bool) (map[string]interface{}, error) {
|
|
ctx, span := trace.Start(ctx, "qbittorrent.RSS.GetItems")
|
|
defer span.End()
|
|
|
|
var apiUrl = fmt.Sprintf("%s/api/v2/rss/items?withData=%t", c.config.Address, withData)
|
|
result, err := c.doRequest(ctx, &requestData{
|
|
url: apiUrl,
|
|
method: http.MethodGet,
|
|
})
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
if result.code != 200 {
|
|
return nil, errors.New("get rss items failed: " + string(result.body))
|
|
}
|
|
var data = make(map[string]interface{})
|
|
err = json.Unmarshal(result.body, &data)
|
|
return data, err
|
|
}
|
|
|
|
func (c *client) MarkAsRead(ctx context.Context, opt *RssMarkAsReadOption) error {
|
|
ctx, span := trace.Start(ctx, "qbittorrent.RSS.MarkAsRead")
|
|
defer span.End()
|
|
|
|
var formData = url.Values{}
|
|
err := encoder.Encode(opt, formData)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
var apiUrl = fmt.Sprintf("%s/api/v2/rss/markAsRead", c.config.Address)
|
|
result, err := c.doRequest(ctx, &requestData{
|
|
url: apiUrl,
|
|
method: http.MethodPost,
|
|
body: strings.NewReader(formData.Encode()),
|
|
})
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
if result.code != 200 {
|
|
return errors.New("mark as read rss item failed: " + string(result.body))
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func (c *client) RefreshItem(ctx context.Context, itemPath string) error {
|
|
ctx, span := trace.Start(ctx, "qbittorrent.RSS.RefreshItem")
|
|
defer span.End()
|
|
|
|
var formData = url.Values{}
|
|
formData.Add("itemPath", itemPath)
|
|
var apiUrl = fmt.Sprintf("%s/api/v2/rss/refreshItem", c.config.Address)
|
|
result, err := c.doRequest(ctx, &requestData{
|
|
url: apiUrl,
|
|
method: http.MethodPost,
|
|
body: strings.NewReader(formData.Encode()),
|
|
})
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
if result.code != 200 {
|
|
return errors.New("refresh rss item failed: " + string(result.body))
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func (c *client) SetAutoDownloadingRule(ctx context.Context, ruleName string, ruleDef *RssAutoDownloadingRuleDef) error {
|
|
ctx, span := trace.Start(ctx, "qbittorrent.RSS.SetAutoDownloadingRule")
|
|
defer span.End()
|
|
|
|
var formData = url.Values{}
|
|
formData.Add("ruleName", ruleName)
|
|
ruleDefBytes, err := json.Marshal(ruleDef)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
formData.Add("ruleDef", string(ruleDefBytes))
|
|
var apiUrl = fmt.Sprintf("%s/api/v2/rss/setRule", c.config.Address)
|
|
result, err := c.doRequest(ctx, &requestData{
|
|
url: apiUrl,
|
|
method: http.MethodPost,
|
|
body: strings.NewReader(formData.Encode()),
|
|
})
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
if result.code != 200 {
|
|
return errors.New("set auto downloading rule failed: " + string(result.body))
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func (c *client) RenameAutoDownloadingRule(ctx context.Context, ruleName, newRuleName string) error {
|
|
ctx, span := trace.Start(ctx, "qbittorrent.RSS.RenameAutoDownloadingRule")
|
|
defer span.End()
|
|
|
|
var formData = url.Values{}
|
|
formData.Add("ruleName", ruleName)
|
|
formData.Add("newRuleName", newRuleName)
|
|
var apiUrl = fmt.Sprintf("%s/api/v2/rss/renameRule", c.config.Address)
|
|
result, err := c.doRequest(ctx, &requestData{
|
|
url: apiUrl,
|
|
method: http.MethodPost,
|
|
body: strings.NewReader(formData.Encode()),
|
|
})
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
if result.code != 200 {
|
|
return errors.New("rename auto downloading rule failed: " + string(result.body))
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func (c *client) RemoveAutoDownloadingRule(ctx context.Context, ruleName string) error {
|
|
ctx, span := trace.Start(ctx, "qbittorrent.RSS.RemoveAutoDownloadingRule")
|
|
defer span.End()
|
|
|
|
var formData = url.Values{}
|
|
formData.Add("ruleName", ruleName)
|
|
var apiUrl = fmt.Sprintf("%s/api/v2/rss/removeRule", c.config.Address)
|
|
result, err := c.doRequest(ctx, &requestData{
|
|
url: apiUrl,
|
|
method: http.MethodPost,
|
|
body: strings.NewReader(formData.Encode()),
|
|
})
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
if result.code != 200 {
|
|
return errors.New("remove auto downloading rule failed: " + string(result.body))
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func (c *client) GetAllAutoDownloadingRules(ctx context.Context) (map[string]*RssAutoDownloadingRuleDef, error) {
|
|
ctx, span := trace.Start(ctx, "qbittorrent.RSS.GetAllAutoDownloadingRules")
|
|
defer span.End()
|
|
|
|
var apiUrl = fmt.Sprintf("%s/api/v2/rss/matchingArticles", c.config.Address)
|
|
result, err := c.doRequest(ctx, &requestData{
|
|
url: apiUrl,
|
|
})
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
if result.code != 200 {
|
|
return nil, errors.New("get rss rules failed: " + string(result.body))
|
|
}
|
|
var data = make(map[string]*RssAutoDownloadingRuleDef)
|
|
err = json.Unmarshal(result.body, &data)
|
|
return data, err
|
|
}
|
|
|
|
func (c *client) GetAllArticlesMatchingRule(ctx context.Context, ruleName string) (map[string][]string, error) {
|
|
ctx, span := trace.Start(ctx, "qbittorrent.RSS.GetAllArticlesMatchingRule")
|
|
defer span.End()
|
|
|
|
var formData = url.Values{}
|
|
formData.Add("ruleName", ruleName)
|
|
var apiUrl = fmt.Sprintf("%s/api/v2/rss/matchingArticles?%s", c.config.Address, formData.Encode())
|
|
result, err := c.doRequest(ctx, &requestData{
|
|
url: apiUrl,
|
|
})
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
if result.code != 200 {
|
|
return nil, errors.New("get rss rule match articles failed: " + string(result.body))
|
|
}
|
|
var data = make(map[string][]string)
|
|
err = json.Unmarshal(result.body, &data)
|
|
return data, err
|
|
}
|