tstor/pkg/qbittorrent/rss.go
2024-09-08 21:39:11 +03:00

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
}