mirror of
https://github.com/idanoo/autobrr
synced 2025-07-22 16:29:12 +00:00

* feat(lists): integrate Omegabrr * feat(lists): add missing lists index * feat(lists): add db repo * feat(lists): add db migrations * feat(lists): labels * feat(lists): url lists and more arrs * fix(lists): db migrations client_id wrong type * fix(lists): db fields * feat(lists): create list form wip * feat(lists): show in list and create * feat(lists): update and delete * feat(lists): trigger via webhook * feat(lists): add webhook handler * fix(arr): encode json to pointer * feat(lists): rename endpoint to lists * feat(lists): fetch tags from arr * feat(lists): process plaintext lists * feat(lists): add background refresh job * run every 6th hour with a random start delay between 1-35 seconds * feat(lists): refresh on save and improve logging * feat(lists): cast arr client to pointer * feat(lists): improve error handling * feat(lists): reset shows field with match release * feat(lists): filter opts all lists * feat(lists): trigger on update if enabled * feat(lists): update option for lists * feat(lists): show connected filters in list * feat(lists): missing listSvc dep * feat(lists): cleanup * feat(lists): typo arr list * feat(lists): radarr include original * feat(lists): rename ExcludeAlternateTitle to IncludeAlternateTitle * fix(lists): arr client type conversion to pointer * fix(actions): only log panic recover if err not nil * feat(lists): show spinner on save * feat(lists): show icon in filters list * feat(lists): change icon color in filters list * feat(lists): delete relations on filter delete
133 lines
3.8 KiB
Go
133 lines
3.8 KiB
Go
package domain
|
|
|
|
import (
|
|
"context"
|
|
"net/http"
|
|
"net/url"
|
|
"strings"
|
|
"time"
|
|
|
|
"github.com/autobrr/autobrr/pkg/errors"
|
|
)
|
|
|
|
type ListRepo interface {
|
|
List(ctx context.Context) ([]*List, error)
|
|
FindByID(ctx context.Context, listID int64) (*List, error)
|
|
Store(ctx context.Context, listID *List) error
|
|
Update(ctx context.Context, listID *List) error
|
|
UpdateLastRefresh(ctx context.Context, list *List) error
|
|
ToggleEnabled(ctx context.Context, listID int64, enabled bool) error
|
|
Delete(ctx context.Context, listID int64) error
|
|
GetListFilters(ctx context.Context, listID int64) ([]ListFilter, error)
|
|
}
|
|
|
|
type ListType string
|
|
|
|
const (
|
|
ListTypeRadarr ListType = "RADARR"
|
|
ListTypeSonarr ListType = "SONARR"
|
|
ListTypeLidarr ListType = "LIDARR"
|
|
ListTypeReadarr ListType = "READARR"
|
|
ListTypeWhisparr ListType = "WHISPARR"
|
|
ListTypeMDBList ListType = "MDBLIST"
|
|
ListTypeMetacritic ListType = "METACRITIC"
|
|
ListTypePlaintext ListType = "PLAINTEXT"
|
|
ListTypeTrakt ListType = "TRAKT"
|
|
ListTypeSteam ListType = "STEAM"
|
|
)
|
|
|
|
type ListRefreshStatus string
|
|
|
|
const (
|
|
ListRefreshStatusSuccess ListRefreshStatus = "SUCCESS"
|
|
ListRefreshStatusError ListRefreshStatus = "ERROR"
|
|
)
|
|
|
|
type List struct {
|
|
ID int64 `json:"id"`
|
|
Name string `json:"name"`
|
|
Type ListType `json:"type"`
|
|
Enabled bool `json:"enabled"`
|
|
ClientID int `json:"client_id"`
|
|
URL string `json:"url"`
|
|
Headers []string `json:"headers"`
|
|
APIKey string `json:"api_key"`
|
|
Filters []ListFilter `json:"filters"`
|
|
MatchRelease bool `json:"match_release"`
|
|
TagsInclude []string `json:"tags_included"`
|
|
TagsExclude []string `json:"tags_excluded"`
|
|
IncludeUnmonitored bool `json:"include_unmonitored"`
|
|
IncludeAlternateTitles bool `json:"include_alternate_titles"`
|
|
LastRefreshTime time.Time `json:"last_refresh_time"`
|
|
LastRefreshData string `json:"last_refresh_error"`
|
|
LastRefreshStatus ListRefreshStatus `json:"last_refresh_status"`
|
|
CreatedAt time.Time `json:"created_at"`
|
|
UpdatedAt time.Time `json:"updated_at"`
|
|
}
|
|
|
|
func (l *List) Validate() error {
|
|
if l.Name == "" {
|
|
return errors.New("name is required")
|
|
}
|
|
|
|
if l.Type == "" {
|
|
return errors.New("type is required")
|
|
}
|
|
|
|
if !l.ListTypeArr() && !l.ListTypeList() {
|
|
return errors.New("invalid list type: %s", l.Type)
|
|
}
|
|
|
|
if l.ListTypeArr() && l.ClientID == 0 {
|
|
return errors.New("arr client id is required")
|
|
}
|
|
|
|
if l.ListTypeList() {
|
|
if l.URL == "" {
|
|
return errors.New("list url is required")
|
|
}
|
|
|
|
_, err := url.Parse(l.URL)
|
|
if err != nil {
|
|
return errors.Wrap(err, "could not parse list url: %s", l.URL)
|
|
}
|
|
}
|
|
|
|
if len(l.Filters) == 0 {
|
|
return errors.New("at least one filter is required")
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
func (l *List) ListTypeArr() bool {
|
|
return l.Type == ListTypeRadarr || l.Type == ListTypeSonarr || l.Type == ListTypeLidarr || l.Type == ListTypeReadarr || l.Type == ListTypeWhisparr
|
|
}
|
|
|
|
func (l *List) ListTypeList() bool {
|
|
return l.Type == ListTypeMDBList || l.Type == ListTypeMetacritic || l.Type == ListTypePlaintext || l.Type == ListTypeTrakt || l.Type == ListTypeSteam
|
|
}
|
|
|
|
func (l *List) ShouldProcessItem(monitored bool) bool {
|
|
if l.IncludeUnmonitored {
|
|
return true
|
|
}
|
|
|
|
return monitored
|
|
}
|
|
|
|
// SetRequestHeaders set headers from list on the request
|
|
func (l *List) SetRequestHeaders(req *http.Request) {
|
|
for _, header := range l.Headers {
|
|
parts := strings.Split(header, "=")
|
|
if len(parts) != 2 {
|
|
continue
|
|
}
|
|
req.Header.Set(parts[0], parts[1])
|
|
}
|
|
}
|
|
|
|
type ListFilter struct {
|
|
ID int `json:"id"`
|
|
Name string `json:"name"`
|
|
}
|