autobrr/internal/domain/list.go
ze0s 221bc35371
feat(lists): integrate Omegabrr (#1885)
* 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
2024-12-25 13:23:37 +01:00

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"`
}