- IMplement multi-download api tokens
- Move things around a bit
This commit is contained in:
230
pkg/debrid/types/account.go
Normal file
230
pkg/debrid/types/account.go
Normal file
@@ -0,0 +1,230 @@
|
||||
package types
|
||||
|
||||
import (
|
||||
"github.com/sirrobot01/decypharr/internal/config"
|
||||
"sync"
|
||||
"time"
|
||||
)
|
||||
|
||||
type Accounts struct {
|
||||
current *Account
|
||||
accounts []*Account
|
||||
mu sync.RWMutex
|
||||
}
|
||||
|
||||
func NewAccounts(debridConf config.Debrid) *Accounts {
|
||||
accounts := make([]*Account, 0)
|
||||
for idx, token := range debridConf.DownloadAPIKeys {
|
||||
if token == "" {
|
||||
continue
|
||||
}
|
||||
account := newAccount(token, idx)
|
||||
accounts = append(accounts, account)
|
||||
}
|
||||
|
||||
var current *Account
|
||||
if len(accounts) > 0 {
|
||||
current = accounts[0]
|
||||
}
|
||||
return &Accounts{
|
||||
accounts: accounts,
|
||||
current: current,
|
||||
}
|
||||
}
|
||||
|
||||
type Account struct {
|
||||
Order int
|
||||
Disabled bool
|
||||
Token string
|
||||
links map[string]*DownloadLink
|
||||
mu sync.RWMutex
|
||||
}
|
||||
|
||||
func (a *Accounts) All() []*Account {
|
||||
a.mu.RLock()
|
||||
defer a.mu.RUnlock()
|
||||
activeAccounts := make([]*Account, 0)
|
||||
for _, acc := range a.accounts {
|
||||
if !acc.Disabled {
|
||||
activeAccounts = append(activeAccounts, acc)
|
||||
}
|
||||
}
|
||||
return activeAccounts
|
||||
}
|
||||
|
||||
func (a *Accounts) Current() *Account {
|
||||
a.mu.RLock()
|
||||
if a.current != nil {
|
||||
current := a.current
|
||||
a.mu.RUnlock()
|
||||
return current
|
||||
}
|
||||
a.mu.RUnlock()
|
||||
|
||||
a.mu.Lock()
|
||||
defer a.mu.Unlock()
|
||||
|
||||
// Double-check after acquiring write lock
|
||||
if a.current != nil {
|
||||
return a.current
|
||||
}
|
||||
|
||||
activeAccounts := make([]*Account, 0)
|
||||
for _, acc := range a.accounts {
|
||||
if !acc.Disabled {
|
||||
activeAccounts = append(activeAccounts, acc)
|
||||
}
|
||||
}
|
||||
|
||||
if len(activeAccounts) > 0 {
|
||||
a.current = activeAccounts[0]
|
||||
}
|
||||
return a.current
|
||||
}
|
||||
|
||||
func (a *Accounts) Disable(account *Account) {
|
||||
a.mu.Lock()
|
||||
defer a.mu.Unlock()
|
||||
account.disable()
|
||||
|
||||
if a.current == account {
|
||||
var newCurrent *Account
|
||||
for _, acc := range a.accounts {
|
||||
if !acc.Disabled {
|
||||
newCurrent = acc
|
||||
break
|
||||
}
|
||||
}
|
||||
a.current = newCurrent
|
||||
}
|
||||
}
|
||||
|
||||
func (a *Accounts) Reset() {
|
||||
a.mu.Lock()
|
||||
defer a.mu.Unlock()
|
||||
for _, acc := range a.accounts {
|
||||
acc.resetDownloadLinks()
|
||||
acc.Disabled = false
|
||||
}
|
||||
if len(a.accounts) > 0 {
|
||||
a.current = a.accounts[0]
|
||||
} else {
|
||||
a.current = nil
|
||||
}
|
||||
}
|
||||
|
||||
func (a *Accounts) GetDownloadLink(fileLink string) (*DownloadLink, error) {
|
||||
if a.Current() == nil {
|
||||
return nil, NoActiveAccountsError
|
||||
}
|
||||
dl, ok := a.Current().getLink(fileLink)
|
||||
if !ok {
|
||||
return nil, NoDownloadLinkError
|
||||
}
|
||||
if dl.ExpiresAt.IsZero() || dl.ExpiresAt.Before(time.Now()) {
|
||||
return nil, DownloadLinkExpiredError
|
||||
}
|
||||
if dl.DownloadLink == "" {
|
||||
return nil, EmptyDownloadLinkError
|
||||
}
|
||||
return dl, nil
|
||||
}
|
||||
|
||||
func (a *Accounts) GetDownloadLinkWithAccount(fileLink string) (*DownloadLink, *Account, error) {
|
||||
currentAccount := a.Current()
|
||||
if currentAccount == nil {
|
||||
return nil, nil, NoActiveAccountsError
|
||||
}
|
||||
dl, ok := currentAccount.getLink(fileLink)
|
||||
if !ok {
|
||||
return nil, nil, NoDownloadLinkError
|
||||
}
|
||||
if dl.ExpiresAt.IsZero() || dl.ExpiresAt.Before(time.Now()) {
|
||||
return nil, currentAccount, DownloadLinkExpiredError
|
||||
}
|
||||
if dl.DownloadLink == "" {
|
||||
return nil, currentAccount, EmptyDownloadLinkError
|
||||
}
|
||||
return dl, currentAccount, nil
|
||||
}
|
||||
|
||||
func (a *Accounts) SetDownloadLink(fileLink string, dl *DownloadLink) {
|
||||
if a.Current() == nil {
|
||||
return
|
||||
}
|
||||
a.Current().setLink(fileLink, dl)
|
||||
}
|
||||
|
||||
func (a *Accounts) DeleteDownloadLink(fileLink string) {
|
||||
if a.Current() == nil {
|
||||
return
|
||||
}
|
||||
a.Current().deleteLink(fileLink)
|
||||
}
|
||||
|
||||
func (a *Accounts) GetLinksCount() int {
|
||||
if a.Current() == nil {
|
||||
return 0
|
||||
}
|
||||
return a.Current().LinksCount()
|
||||
}
|
||||
|
||||
func (a *Accounts) SetDownloadLinks(links map[string]*DownloadLink) {
|
||||
if a.Current() == nil {
|
||||
return
|
||||
}
|
||||
a.Current().setLinks(links)
|
||||
}
|
||||
|
||||
func newAccount(token string, index int) *Account {
|
||||
return &Account{
|
||||
Token: token,
|
||||
Order: index,
|
||||
links: make(map[string]*DownloadLink),
|
||||
}
|
||||
}
|
||||
|
||||
func (a *Account) getLink(fileLink string) (*DownloadLink, bool) {
|
||||
a.mu.RLock()
|
||||
defer a.mu.RUnlock()
|
||||
dl, ok := a.links[fileLink[0:39]]
|
||||
return dl, ok
|
||||
}
|
||||
func (a *Account) setLink(fileLink string, dl *DownloadLink) {
|
||||
a.mu.Lock()
|
||||
defer a.mu.Unlock()
|
||||
a.links[fileLink[0:39]] = dl
|
||||
}
|
||||
func (a *Account) deleteLink(fileLink string) {
|
||||
a.mu.Lock()
|
||||
defer a.mu.Unlock()
|
||||
|
||||
delete(a.links, fileLink[0:39])
|
||||
}
|
||||
func (a *Account) resetDownloadLinks() {
|
||||
a.mu.Lock()
|
||||
defer a.mu.Unlock()
|
||||
a.links = make(map[string]*DownloadLink)
|
||||
}
|
||||
func (a *Account) LinksCount() int {
|
||||
a.mu.RLock()
|
||||
defer a.mu.RUnlock()
|
||||
return len(a.links)
|
||||
}
|
||||
|
||||
func (a *Account) disable() {
|
||||
a.Disabled = true
|
||||
}
|
||||
|
||||
func (a *Account) setLinks(links map[string]*DownloadLink) {
|
||||
a.mu.Lock()
|
||||
defer a.mu.Unlock()
|
||||
now := time.Now()
|
||||
for _, dl := range links {
|
||||
if !dl.ExpiresAt.IsZero() && dl.ExpiresAt.Before(now) {
|
||||
// Expired, continue
|
||||
continue
|
||||
}
|
||||
a.links[dl.Link[0:39]] = dl
|
||||
}
|
||||
}
|
||||
@@ -7,11 +7,10 @@ import (
|
||||
type Client interface {
|
||||
SubmitMagnet(tr *Torrent) (*Torrent, error)
|
||||
CheckStatus(tr *Torrent, isSymlink bool) (*Torrent, error)
|
||||
GenerateDownloadLinks(tr *Torrent) error
|
||||
GetFileDownloadLinks(tr *Torrent) error
|
||||
GetDownloadLink(tr *Torrent, file *File) (*DownloadLink, error)
|
||||
DeleteTorrent(torrentId string) error
|
||||
IsAvailable(infohashes []string) map[string]bool
|
||||
GetCheckCached() bool
|
||||
GetDownloadUncached() bool
|
||||
UpdateTorrent(torrent *Torrent) error
|
||||
GetTorrent(torrentId string) (*Torrent, error)
|
||||
@@ -19,11 +18,10 @@ type Client interface {
|
||||
Name() string
|
||||
Logger() zerolog.Logger
|
||||
GetDownloadingStatus() []string
|
||||
GetDownloads() (map[string]DownloadLink, error)
|
||||
GetDownloadLinks() (map[string]*DownloadLink, error)
|
||||
CheckLink(link string) error
|
||||
GetMountPath() string
|
||||
DisableAccount(string)
|
||||
ResetActiveDownloadKeys()
|
||||
Accounts() *Accounts // Returns the active download account/token
|
||||
DeleteDownloadLink(linkId string) error
|
||||
GetProfile() (*Profile, error)
|
||||
GetAvailableSlots() (int, error)
|
||||
|
||||
30
pkg/debrid/types/error.go
Normal file
30
pkg/debrid/types/error.go
Normal file
@@ -0,0 +1,30 @@
|
||||
package types
|
||||
|
||||
type Error struct {
|
||||
Message string `json:"message"`
|
||||
Code string `json:"code"`
|
||||
}
|
||||
|
||||
func (e *Error) Error() string {
|
||||
return e.Message
|
||||
}
|
||||
|
||||
var NoActiveAccountsError = &Error{
|
||||
Message: "No active accounts",
|
||||
Code: "no_active_accounts",
|
||||
}
|
||||
|
||||
var NoDownloadLinkError = &Error{
|
||||
Message: "No download link found",
|
||||
Code: "no_download_link",
|
||||
}
|
||||
|
||||
var DownloadLinkExpiredError = &Error{
|
||||
Message: "Download link expired",
|
||||
Code: "download_link_expired",
|
||||
}
|
||||
|
||||
var EmptyDownloadLinkError = &Error{
|
||||
Message: "Download link is empty",
|
||||
Code: "empty_download_link",
|
||||
}
|
||||
@@ -42,20 +42,6 @@ type Torrent struct {
|
||||
sync.Mutex
|
||||
}
|
||||
|
||||
type DownloadLink struct {
|
||||
Filename string `json:"filename"`
|
||||
Link string `json:"link"`
|
||||
DownloadLink string `json:"download_link"`
|
||||
Generated time.Time `json:"generated"`
|
||||
Size int64 `json:"size"`
|
||||
Id string `json:"id"`
|
||||
AccountId string `json:"account_id"`
|
||||
}
|
||||
|
||||
func (d *DownloadLink) String() string {
|
||||
return d.DownloadLink
|
||||
}
|
||||
|
||||
func (t *Torrent) GetSymlinkFolder(parent string) string {
|
||||
return filepath.Join(parent, t.Arr.Name, t.Folder)
|
||||
}
|
||||
@@ -106,10 +92,10 @@ type File struct {
|
||||
ByteRange *[2]int64 `json:"byte_range,omitempty"`
|
||||
Path string `json:"path"`
|
||||
Link string `json:"link"`
|
||||
DownloadLink *DownloadLink `json:"-"`
|
||||
AccountId string `json:"account_id"`
|
||||
Generated time.Time `json:"generated"`
|
||||
Deleted bool `json:"deleted"`
|
||||
DownloadLink *DownloadLink `json:"-"`
|
||||
}
|
||||
|
||||
func (t *Torrent) Cleanup(remove bool) {
|
||||
@@ -121,13 +107,6 @@ func (t *Torrent) Cleanup(remove bool) {
|
||||
}
|
||||
}
|
||||
|
||||
type Account struct {
|
||||
ID string `json:"id"`
|
||||
Disabled bool `json:"disabled"`
|
||||
Name string `json:"name"`
|
||||
Token string `json:"token"`
|
||||
}
|
||||
|
||||
type IngestData struct {
|
||||
Debrid string `json:"debrid"`
|
||||
Name string `json:"name"`
|
||||
@@ -149,3 +128,17 @@ type Profile struct {
|
||||
BadTorrents int `json:"bad_torrents"`
|
||||
ActiveLinks int `json:"active_links"`
|
||||
}
|
||||
|
||||
type DownloadLink struct {
|
||||
Filename string `json:"filename"`
|
||||
Link string `json:"link"`
|
||||
DownloadLink string `json:"download_link"`
|
||||
Generated time.Time `json:"generated"`
|
||||
Size int64 `json:"size"`
|
||||
Id string `json:"id"`
|
||||
ExpiresAt time.Time
|
||||
}
|
||||
|
||||
func (d *DownloadLink) String() string {
|
||||
return d.DownloadLink
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user