feat(indexers): add External Identifier to map with ARR indexers (#1534)

* feat(indexers): add External Identifier to map with ARR indexers

* fix: web build

* fix: tests

* feat: set identifier for manual processing
This commit is contained in:
ze0s 2024-05-04 12:37:01 +02:00 committed by GitHub
parent ad6ef228ec
commit 0016228d89
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
26 changed files with 254 additions and 197 deletions

View file

@ -82,9 +82,10 @@ func Test_service_execCmd(t *testing.T) {
TorrentName: "This is a test", TorrentName: "This is a test",
TorrentTmpFile: "tmp-10000", TorrentTmpFile: "tmp-10000",
Indexer: domain.IndexerMinimal{ Indexer: domain.IndexerMinimal{
ID: 0, ID: 0,
Name: "Mock Indexer", Name: "Mock Indexer",
Identifier: "mock", Identifier: "mock",
IdentifierExternal: "Mock Indexer",
}, },
}, },
action: &domain.Action{ action: &domain.Action{

View file

@ -59,7 +59,7 @@ func (s *service) lidarr(ctx context.Context, action *domain.Action, release dom
DownloadUrl: release.DownloadURL, DownloadUrl: release.DownloadURL,
MagnetUrl: release.MagnetURI, MagnetUrl: release.MagnetURI,
Size: int64(release.Size), Size: int64(release.Size),
Indexer: release.Indexer.Identifier, Indexer: release.Indexer.IdentifierExternal,
DownloadClientId: externalClientId, DownloadClientId: externalClientId,
DownloadClient: externalClient, DownloadClient: externalClient,
DownloadProtocol: string(release.Protocol), DownloadProtocol: string(release.Protocol),

View file

@ -58,7 +58,7 @@ func (s *service) radarr(ctx context.Context, action *domain.Action, release dom
DownloadUrl: release.DownloadURL, DownloadUrl: release.DownloadURL,
MagnetUrl: release.MagnetURI, MagnetUrl: release.MagnetURI,
Size: int64(release.Size), Size: int64(release.Size),
Indexer: release.Indexer.Identifier, Indexer: release.Indexer.IdentifierExternal,
DownloadClientId: externalClientId, DownloadClientId: externalClientId,
DownloadClient: externalClient, DownloadClient: externalClient,
DownloadProtocol: string(release.Protocol), DownloadProtocol: string(release.Protocol),

View file

@ -58,7 +58,7 @@ func (s *service) readarr(ctx context.Context, action *domain.Action, release do
DownloadUrl: release.DownloadURL, DownloadUrl: release.DownloadURL,
MagnetUrl: release.MagnetURI, MagnetUrl: release.MagnetURI,
Size: int64(release.Size), Size: int64(release.Size),
Indexer: release.Indexer.Identifier, Indexer: release.Indexer.IdentifierExternal,
DownloadClientId: externalClientId, DownloadClientId: externalClientId,
DownloadClient: externalClient, DownloadClient: externalClient,
DownloadProtocol: string(release.Protocol), DownloadProtocol: string(release.Protocol),

View file

@ -58,7 +58,7 @@ func (s *service) sonarr(ctx context.Context, action *domain.Action, release dom
DownloadUrl: release.DownloadURL, DownloadUrl: release.DownloadURL,
MagnetUrl: release.MagnetURI, MagnetUrl: release.MagnetURI,
Size: int64(release.Size), Size: int64(release.Size),
Indexer: release.Indexer.Identifier, Indexer: release.Indexer.IdentifierExternal,
DownloadClientId: externalClientId, DownloadClientId: externalClientId,
DownloadClient: externalClient, DownloadClient: externalClient,
DownloadProtocol: string(release.Protocol), DownloadProtocol: string(release.Protocol),

View file

@ -58,7 +58,7 @@ func (s *service) whisparr(ctx context.Context, action *domain.Action, release d
DownloadUrl: release.DownloadURL, DownloadUrl: release.DownloadURL,
MagnetUrl: release.MagnetURI, MagnetUrl: release.MagnetURI,
Size: int64(release.Size), Size: int64(release.Size),
Indexer: release.Indexer.Identifier, Indexer: release.Indexer.IdentifierExternal,
DownloadClientId: externalClientId, DownloadClientId: externalClientId,
DownloadClient: externalClient, DownloadClient: externalClient,
DownloadProtocol: string(release.Protocol), DownloadProtocol: string(release.Protocol),

View file

@ -103,7 +103,7 @@ func (a *announceProcessor) processQueue(queue chan string) {
continue continue
} }
rls := domain.NewRelease(domain.IndexerMinimal{ID: a.indexer.ID, Name: a.indexer.Name, Identifier: a.indexer.Identifier}) rls := domain.NewRelease(domain.IndexerMinimal{ID: a.indexer.ID, Name: a.indexer.Name, Identifier: a.indexer.Identifier, IdentifierExternal: a.indexer.IdentifierExternal})
rls.Protocol = domain.ReleaseProtocol(a.indexer.Protocol) rls.Protocol = domain.ReleaseProtocol(a.indexer.Protocol)
// on lines matched // on lines matched

View file

@ -34,6 +34,7 @@ func (r *FeedRepo) FindByID(ctx context.Context, id int) (*domain.Feed, error) {
"f.id", "f.id",
"i.id", "i.id",
"i.identifier", "i.identifier",
"i.identifier_external",
"i.name", "i.name",
"f.name", "f.name",
"f.type", "f.type",
@ -66,7 +67,7 @@ func (r *FeedRepo) FindByID(ctx context.Context, id int) (*domain.Feed, error) {
var apiKey, cookie, settings sql.NullString var apiKey, cookie, settings sql.NullString
if err := row.Scan(&f.ID, &f.Indexer.ID, &f.Indexer.Identifier, &f.Indexer.Name, &f.Name, &f.Type, &f.Enabled, &f.URL, &f.Interval, &f.Timeout, &f.MaxAge, &apiKey, &cookie, &settings, &f.CreatedAt, &f.UpdatedAt); err != nil { if err := row.Scan(&f.ID, &f.Indexer.ID, &f.Indexer.Identifier, &f.Indexer.IdentifierExternal, &f.Indexer.Name, &f.Name, &f.Type, &f.Enabled, &f.URL, &f.Interval, &f.Timeout, &f.MaxAge, &apiKey, &cookie, &settings, &f.CreatedAt, &f.UpdatedAt); err != nil {
return nil, errors.Wrap(err, "error scanning row") return nil, errors.Wrap(err, "error scanning row")
} }
@ -91,6 +92,7 @@ func (r *FeedRepo) FindByIndexerIdentifier(ctx context.Context, indexer string)
"f.id", "f.id",
"i.id", "i.id",
"i.identifier", "i.identifier",
"i.identifier_external",
"i.name", "i.name",
"f.name", "f.name",
"f.type", "f.type",
@ -123,7 +125,7 @@ func (r *FeedRepo) FindByIndexerIdentifier(ctx context.Context, indexer string)
var apiKey, cookie, settings sql.NullString var apiKey, cookie, settings sql.NullString
if err := row.Scan(&f.ID, &f.Indexer.ID, &f.Indexer.Identifier, &f.Indexer.Name, &f.Name, &f.Type, &f.Enabled, &f.URL, &f.Interval, &f.Timeout, &f.MaxAge, &apiKey, &cookie, &settings, &f.CreatedAt, &f.UpdatedAt); err != nil { if err := row.Scan(&f.ID, &f.Indexer.ID, &f.Indexer.Identifier, &f.Indexer.IdentifierExternal, &f.Indexer.Name, &f.Name, &f.Type, &f.Enabled, &f.URL, &f.Interval, &f.Timeout, &f.MaxAge, &apiKey, &cookie, &settings, &f.CreatedAt, &f.UpdatedAt); err != nil {
return nil, errors.Wrap(err, "error scanning row") return nil, errors.Wrap(err, "error scanning row")
} }
@ -146,6 +148,7 @@ func (r *FeedRepo) Find(ctx context.Context) ([]domain.Feed, error) {
"f.id", "f.id",
"i.id", "i.id",
"i.identifier", "i.identifier",
"i.identifier_external",
"i.name", "i.name",
"f.name", "f.name",
"f.type", "f.type",
@ -185,7 +188,7 @@ func (r *FeedRepo) Find(ctx context.Context) ([]domain.Feed, error) {
var apiKey, cookie, lastRunData, settings sql.NullString var apiKey, cookie, lastRunData, settings sql.NullString
var lastRun sql.NullTime var lastRun sql.NullTime
if err := rows.Scan(&f.ID, &f.Indexer.ID, &f.Indexer.Identifier, &f.Indexer.Name, &f.Name, &f.Type, &f.Enabled, &f.URL, &f.Interval, &f.Timeout, &f.MaxAge, &apiKey, &cookie, &lastRun, &lastRunData, &settings, &f.CreatedAt, &f.UpdatedAt); err != nil { if err := rows.Scan(&f.ID, &f.Indexer.ID, &f.Indexer.Identifier, &f.Indexer.IdentifierExternal, &f.Indexer.Name, &f.Name, &f.Type, &f.Enabled, &f.URL, &f.Interval, &f.Timeout, &f.MaxAge, &apiKey, &cookie, &lastRun, &lastRunData, &settings, &f.CreatedAt, &f.UpdatedAt); err != nil {
return nil, errors.Wrap(err, "error scanning row") return nil, errors.Wrap(err, "error scanning row")
} }

View file

@ -36,19 +36,16 @@ func (r *IndexerRepo) Store(ctx context.Context, indexer domain.Indexer) (*domai
} }
queryBuilder := r.db.squirrel. queryBuilder := r.db.squirrel.
Insert("indexer").Columns("enabled", "name", "identifier", "implementation", "base_url", "settings"). Insert("indexer").Columns("enabled", "name", "identifier", "identifier_external", "implementation", "base_url", "settings").
Values(indexer.Enabled, indexer.Name, indexer.Identifier, indexer.Implementation, indexer.BaseURL, settings). Values(indexer.Enabled, indexer.Name, indexer.Identifier, indexer.IdentifierExternal, indexer.Implementation, indexer.BaseURL, settings).
Suffix("RETURNING id").RunWith(r.db.handler) Suffix("RETURNING id").RunWith(r.db.handler)
// return values // return values
var retID int64 err = queryBuilder.QueryRowContext(ctx).Scan(&indexer.ID)
if err != nil {
if err = queryBuilder.QueryRowContext(ctx).Scan(&retID); err != nil {
return nil, errors.Wrap(err, "error executing query") return nil, errors.Wrap(err, "error executing query")
} }
indexer.ID = retID
return &indexer, nil return &indexer, nil
} }
@ -62,6 +59,7 @@ func (r *IndexerRepo) Update(ctx context.Context, indexer domain.Indexer) (*doma
Update("indexer"). Update("indexer").
Set("enabled", indexer.Enabled). Set("enabled", indexer.Enabled).
Set("name", indexer.Name). Set("name", indexer.Name).
Set("identifier_external", indexer.IdentifierExternal).
Set("base_url", indexer.BaseURL). Set("base_url", indexer.BaseURL).
Set("settings", settings). Set("settings", settings).
Set("updated_at", time.Now().Format(time.RFC3339)). Set("updated_at", time.Now().Format(time.RFC3339)).
@ -81,7 +79,7 @@ func (r *IndexerRepo) Update(ctx context.Context, indexer domain.Indexer) (*doma
func (r *IndexerRepo) List(ctx context.Context) ([]domain.Indexer, error) { func (r *IndexerRepo) List(ctx context.Context) ([]domain.Indexer, error) {
queryBuilder := r.db.squirrel. queryBuilder := r.db.squirrel.
Select("id", "enabled", "name", "identifier", "implementation", "base_url", "settings"). Select("id", "enabled", "name", "identifier", "identifier_external", "implementation", "base_url", "settings").
From("indexer"). From("indexer").
OrderBy("name ASC") OrderBy("name ASC")
@ -102,16 +100,17 @@ func (r *IndexerRepo) List(ctx context.Context) ([]domain.Indexer, error) {
for rows.Next() { for rows.Next() {
var f domain.Indexer var f domain.Indexer
var implementation, baseURL sql.NullString var identifierExternal, implementation, baseURL sql.Null[string]
var settings string var settings string
var settingsMap map[string]string var settingsMap map[string]string
if err := rows.Scan(&f.ID, &f.Enabled, &f.Name, &f.Identifier, &implementation, &baseURL, &settings); err != nil { if err := rows.Scan(&f.ID, &f.Enabled, &f.Name, &f.Identifier, &identifierExternal, &implementation, &baseURL, &settings); err != nil {
return nil, errors.Wrap(err, "error scanning row") return nil, errors.Wrap(err, "error scanning row")
} }
f.Implementation = implementation.String f.IdentifierExternal = identifierExternal.V
f.BaseURL = baseURL.String f.Implementation = implementation.V
f.BaseURL = baseURL.V
if err = json.Unmarshal([]byte(settings), &settingsMap); err != nil { if err = json.Unmarshal([]byte(settings), &settingsMap); err != nil {
return nil, errors.Wrap(err, "error unmarshal settings") return nil, errors.Wrap(err, "error unmarshal settings")
@ -130,7 +129,7 @@ func (r *IndexerRepo) List(ctx context.Context) ([]domain.Indexer, error) {
func (r *IndexerRepo) FindByID(ctx context.Context, id int) (*domain.Indexer, error) { func (r *IndexerRepo) FindByID(ctx context.Context, id int) (*domain.Indexer, error) {
queryBuilder := r.db.squirrel. queryBuilder := r.db.squirrel.
Select("id", "enabled", "name", "identifier", "implementation", "base_url", "settings"). Select("id", "enabled", "name", "identifier", "identifier_external", "implementation", "base_url", "settings").
From("indexer"). From("indexer").
Where(sq.Eq{"id": id}) Where(sq.Eq{"id": id})
@ -146,17 +145,18 @@ func (r *IndexerRepo) FindByID(ctx context.Context, id int) (*domain.Indexer, er
var i domain.Indexer var i domain.Indexer
var implementation, baseURL, settings sql.NullString var identifierExternal, implementation, baseURL, settings sql.Null[string]
if err := row.Scan(&i.ID, &i.Enabled, &i.Name, &i.Identifier, &implementation, &baseURL, &settings); err != nil { if err := row.Scan(&i.ID, &i.Enabled, &i.Name, &i.Identifier, &identifierExternal, &implementation, &baseURL, &settings); err != nil {
return nil, errors.Wrap(err, "error scanning row") return nil, errors.Wrap(err, "error scanning row")
} }
i.Implementation = implementation.String i.IdentifierExternal = identifierExternal.V
i.BaseURL = baseURL.String i.Implementation = implementation.V
i.BaseURL = baseURL.V
var settingsMap map[string]string var settingsMap map[string]string
if err = json.Unmarshal([]byte(settings.String), &settingsMap); err != nil { if err = json.Unmarshal([]byte(settings.V), &settingsMap); err != nil {
return nil, errors.Wrap(err, "error unmarshal settings") return nil, errors.Wrap(err, "error unmarshal settings")
} }
@ -167,7 +167,7 @@ func (r *IndexerRepo) FindByID(ctx context.Context, id int) (*domain.Indexer, er
func (r *IndexerRepo) FindByFilterID(ctx context.Context, id int) ([]domain.Indexer, error) { func (r *IndexerRepo) FindByFilterID(ctx context.Context, id int) ([]domain.Indexer, error) {
queryBuilder := r.db.squirrel. queryBuilder := r.db.squirrel.
Select("id", "enabled", "name", "identifier", "base_url", "settings"). Select("id", "enabled", "name", "identifier", "identifier_external", "base_url", "settings").
From("indexer"). From("indexer").
Join("filter_indexer ON indexer.id = filter_indexer.indexer_id"). Join("filter_indexer ON indexer.id = filter_indexer.indexer_id").
Where(sq.Eq{"filter_indexer.filter_id": id}) Where(sq.Eq{"filter_indexer.filter_id": id})
@ -190,9 +190,9 @@ func (r *IndexerRepo) FindByFilterID(ctx context.Context, id int) ([]domain.Inde
var settings string var settings string
var settingsMap map[string]string var settingsMap map[string]string
var baseURL sql.NullString var identifierExternal, baseURL sql.Null[string]
if err := rows.Scan(&f.ID, &f.Enabled, &f.Name, &f.Identifier, &baseURL, &settings); err != nil { if err := rows.Scan(&f.ID, &f.Enabled, &f.Name, &f.Identifier, &identifierExternal, &baseURL, &settings); err != nil {
return nil, errors.Wrap(err, "error scanning row") return nil, errors.Wrap(err, "error scanning row")
} }
@ -200,7 +200,8 @@ func (r *IndexerRepo) FindByFilterID(ctx context.Context, id int) ([]domain.Inde
return nil, errors.Wrap(err, "error unmarshal settings") return nil, errors.Wrap(err, "error unmarshal settings")
} }
f.BaseURL = baseURL.String f.IdentifierExternal = identifierExternal.V
f.BaseURL = baseURL.V
f.Settings = settingsMap f.Settings = settingsMap
indexers = append(indexers, f) indexers = append(indexers, f)

View file

@ -16,15 +16,16 @@ CREATE TABLE users
CREATE TABLE indexer CREATE TABLE indexer
( (
id SERIAL PRIMARY KEY, id SERIAL PRIMARY KEY,
identifier TEXT, identifier TEXT,
implementation TEXT, identifier_external TEXT,
base_url TEXT, implementation TEXT,
enabled BOOLEAN, base_url TEXT,
name TEXT NOT NULL, enabled BOOLEAN,
settings TEXT, name TEXT NOT NULL,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, settings TEXT,
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
UNIQUE (identifier) UNIQUE (identifier)
); );
@ -877,5 +878,11 @@ ALTER TABLE filter
`, `,
`ALTER TABLE action `ALTER TABLE action
ADD COLUMN first_last_piece_prio BOOLEAN DEFAULT false; ADD COLUMN first_last_piece_prio BOOLEAN DEFAULT false;
`,
`ALTER TABLE indexer
ADD COLUMN identifier_external TEXT;
UPDATE indexer
SET identifier_external = name;
`, `,
} }

View file

@ -16,15 +16,16 @@ CREATE TABLE users
CREATE TABLE indexer CREATE TABLE indexer
( (
id INTEGER PRIMARY KEY, id INTEGER PRIMARY KEY,
identifier TEXT, identifier TEXT,
implementation TEXT, identifier_external TEXT,
base_url TEXT, implementation TEXT,
enabled BOOLEAN, base_url TEXT,
name TEXT NOT NULL, enabled BOOLEAN,
settings TEXT, name TEXT NOT NULL,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, settings TEXT,
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
UNIQUE (identifier) UNIQUE (identifier)
); );
@ -1515,5 +1516,11 @@ ALTER TABLE filter
`, `,
`ALTER TABLE action `ALTER TABLE action
ADD COLUMN first_last_piece_prio BOOLEAN DEFAULT false; ADD COLUMN first_last_piece_prio BOOLEAN DEFAULT false;
`,
`ALTER TABLE indexer
ADD COLUMN identifier_external TEXT;
UPDATE indexer
SET identifier_external = name;
`, `,
} }

View file

@ -26,40 +26,43 @@ type IndexerRepo interface {
} }
type Indexer struct { type Indexer struct {
ID int64 `json:"id"` ID int64 `json:"id"`
Name string `json:"name"` Name string `json:"name"`
Identifier string `json:"identifier"` Identifier string `json:"identifier"`
Enabled bool `json:"enabled"` IdentifierExternal string `json:"identifier_external"`
Implementation string `json:"implementation"` Enabled bool `json:"enabled"`
BaseURL string `json:"base_url,omitempty"` Implementation string `json:"implementation"`
Settings map[string]string `json:"settings,omitempty"` BaseURL string `json:"base_url,omitempty"`
Settings map[string]string `json:"settings,omitempty"`
} }
type IndexerMinimal struct { type IndexerMinimal struct {
ID int `json:"id"` ID int `json:"id"`
Name string `json:"name"` Name string `json:"name"`
Identifier string `json:"identifier"` Identifier string `json:"identifier"`
IdentifierExternal string `json:"identifier_external"`
} }
type IndexerDefinition struct { type IndexerDefinition struct {
ID int `json:"id,omitempty"` ID int `json:"id,omitempty"`
Name string `json:"name"` Name string `json:"name"`
Identifier string `json:"identifier"` Identifier string `json:"identifier"`
Implementation string `json:"implementation"` IdentifierExternal string `json:"identifier_external"`
BaseURL string `json:"base_url,omitempty"` Implementation string `json:"implementation"`
Enabled bool `json:"enabled"` BaseURL string `json:"base_url,omitempty"`
Description string `json:"description"` Enabled bool `json:"enabled"`
Language string `json:"language"` Description string `json:"description"`
Privacy string `json:"privacy"` Language string `json:"language"`
Protocol string `json:"protocol"` Privacy string `json:"privacy"`
URLS []string `json:"urls"` Protocol string `json:"protocol"`
Supports []string `json:"supports"` URLS []string `json:"urls"`
Settings []IndexerSetting `json:"settings,omitempty"` Supports []string `json:"supports"`
SettingsMap map[string]string `json:"-"` Settings []IndexerSetting `json:"settings,omitempty"`
IRC *IndexerIRC `json:"irc,omitempty"` SettingsMap map[string]string `json:"-"`
Torznab *Torznab `json:"torznab,omitempty"` IRC *IndexerIRC `json:"irc,omitempty"`
Newznab *Newznab `json:"newznab,omitempty"` Torznab *Torznab `json:"torznab,omitempty"`
RSS *FeedSettings `json:"rss,omitempty"` Newznab *Newznab `json:"newznab,omitempty"`
RSS *FeedSettings `json:"rss,omitempty"`
} }
type IndexerImplementation string type IndexerImplementation string

View file

@ -254,7 +254,7 @@ func TestIRCParserGazelleGames_Parse(t *testing.T) {
{ {
name: "", name: "",
args: args{ args: args{
rls: NewRelease(IndexerMinimal{0, "GazelleGames", "ggn"}), rls: NewRelease(IndexerMinimal{0, "GazelleGames", "ggn", "GazelleGames"}),
vars: map[string]string{ vars: map[string]string{
"torrentName": "Trouble.in.Paradise-GROUP in Trouble in Paradise", "torrentName": "Trouble.in.Paradise-GROUP in Trouble in Paradise",
}, },
@ -267,7 +267,7 @@ func TestIRCParserGazelleGames_Parse(t *testing.T) {
{ {
name: "", name: "",
args: args{ args: args{
rls: NewRelease(IndexerMinimal{0, "GazelleGames", "ggn"}), rls: NewRelease(IndexerMinimal{0, "GazelleGames", "ggn", "GazelleGames"}),
vars: map[string]string{ vars: map[string]string{
"torrentName": "F.I.L.F. Game Walkthrough v.0.18 in F.I.L.F.", "torrentName": "F.I.L.F. Game Walkthrough v.0.18 in F.I.L.F.",
}, },
@ -280,7 +280,7 @@ func TestIRCParserGazelleGames_Parse(t *testing.T) {
{ {
name: "", name: "",
args: args{ args: args{
rls: NewRelease(IndexerMinimal{0, "GazelleGames", "ggn"}), rls: NewRelease(IndexerMinimal{0, "GazelleGames", "ggn", "GazelleGames"}),
vars: map[string]string{ vars: map[string]string{
"torrentName": "Ni no Kuni: Dominion of the Dark Djinn in Ni no Kuni: Dominion of the Dark Djinn", "torrentName": "Ni no Kuni: Dominion of the Dark Djinn in Ni no Kuni: Dominion of the Dark Djinn",
}, },
@ -293,7 +293,7 @@ func TestIRCParserGazelleGames_Parse(t *testing.T) {
{ {
name: "", name: "",
args: args{ args: args{
rls: NewRelease(IndexerMinimal{0, "GazelleGames", "ggn"}), rls: NewRelease(IndexerMinimal{0, "GazelleGames", "ggn", "GazelleGames"}),
vars: map[string]string{ vars: map[string]string{
"torrentName": "Year 2 Remastered by Insaneintherainmusic", "torrentName": "Year 2 Remastered by Insaneintherainmusic",
"category": "OST", "category": "OST",
@ -332,7 +332,7 @@ func TestIRCParserOrpheus_Parse(t *testing.T) {
{ {
name: "", name: "",
args: args{ args: args{
rls: NewRelease(IndexerMinimal{0, "Orpheus", "ops"}), rls: NewRelease(IndexerMinimal{0, "Orpheus", "ops", "Orpheus"}),
vars: map[string]string{ vars: map[string]string{
"torrentName": "Busta Rhymes BEACH BALL (feat. BIA) [2023] [Single] WEB/FLAC/24bit Lossless", "torrentName": "Busta Rhymes BEACH BALL (feat. BIA) [2023] [Single] WEB/FLAC/24bit Lossless",
"title": "Busta Rhymes BEACH BALL (feat. BIA)", "title": "Busta Rhymes BEACH BALL (feat. BIA)",
@ -348,7 +348,7 @@ func TestIRCParserOrpheus_Parse(t *testing.T) {
{ {
name: "", name: "",
args: args{ args: args{
rls: NewRelease(IndexerMinimal{0, "Orpheus", "ops"}), rls: NewRelease(IndexerMinimal{0, "Orpheus", "ops", "Orpheus"}),
vars: map[string]string{ vars: map[string]string{
"torrentName": "Busta Rhymes BEACH BALL (feat. BIA) [2023] [Single] CD/FLAC/Lossless", "torrentName": "Busta Rhymes BEACH BALL (feat. BIA) [2023] [Single] CD/FLAC/Lossless",
"title": "Busta Rhymes BEACH BALL (feat. BIA)", "title": "Busta Rhymes BEACH BALL (feat. BIA)",

View file

@ -16,84 +16,86 @@ import (
) )
type Macro struct { type Macro struct {
TorrentName string TorrentName string
TorrentPathName string TorrentPathName string
TorrentHash string TorrentHash string
TorrentID string TorrentID string
TorrentUrl string TorrentUrl string
TorrentDataRawBytes []byte TorrentDataRawBytes []byte
MagnetURI string MagnetURI string
Group string Group string
GroupID string GroupID string
DownloadUrl string DownloadUrl string
InfoUrl string InfoUrl string
Indexer string Indexer string
IndexerName string IndexerName string
IndexerIdentifier string IndexerIdentifier string
Title string IndexerIdentifierExternal string
Type string Title string
Category string Type string
Categories []string Category string
Resolution string Categories []string
Source string Resolution string
HDR string Source string
FilterID int HDR string
FilterName string FilterID int
Size uint64 FilterName string
SizeString string Size uint64
Season int SizeString string
Episode int Season int
Year int Episode int
CurrentYear int Year int
CurrentMonth int CurrentYear int
CurrentDay int CurrentMonth int
CurrentHour int CurrentDay int
CurrentMinute int CurrentHour int
CurrentSecond int CurrentMinute int
Tags string CurrentSecond int
Artists string Tags string
Artists string
} }
func NewMacro(release Release) Macro { func NewMacro(release Release) Macro {
currentTime := time.Now() currentTime := time.Now()
ma := Macro{ ma := Macro{
TorrentName: release.TorrentName, TorrentName: release.TorrentName,
TorrentUrl: release.DownloadURL, TorrentUrl: release.DownloadURL,
TorrentPathName: release.TorrentTmpFile, TorrentPathName: release.TorrentTmpFile,
TorrentDataRawBytes: release.TorrentDataRawBytes, TorrentDataRawBytes: release.TorrentDataRawBytes,
TorrentHash: release.TorrentHash, TorrentHash: release.TorrentHash,
TorrentID: release.TorrentID, TorrentID: release.TorrentID,
MagnetURI: release.MagnetURI, MagnetURI: release.MagnetURI,
Group: release.Group, Group: release.Group,
GroupID: release.GroupID, GroupID: release.GroupID,
InfoUrl: release.InfoURL, InfoUrl: release.InfoURL,
DownloadUrl: release.DownloadURL, DownloadUrl: release.DownloadURL,
Indexer: release.Indexer.Identifier, Indexer: release.Indexer.Identifier,
IndexerName: release.Indexer.Name, IndexerName: release.Indexer.Name,
IndexerIdentifier: release.Indexer.Identifier, IndexerIdentifier: release.Indexer.Identifier,
Title: release.Title, IndexerIdentifierExternal: release.Indexer.IdentifierExternal,
Type: release.Type, Title: release.Title,
Category: release.Category, Type: release.Type,
Categories: release.Categories, Category: release.Category,
Resolution: release.Resolution, Categories: release.Categories,
Source: release.Source, Resolution: release.Resolution,
HDR: strings.Join(release.HDR, ", "), Source: release.Source,
FilterID: release.FilterID, HDR: strings.Join(release.HDR, ", "),
FilterName: release.FilterName, FilterID: release.FilterID,
Size: release.Size, FilterName: release.FilterName,
SizeString: humanize.Bytes(release.Size), Size: release.Size,
Season: release.Season, SizeString: humanize.Bytes(release.Size),
Episode: release.Episode, Season: release.Season,
Year: release.Year, Episode: release.Episode,
CurrentYear: currentTime.Year(), Year: release.Year,
CurrentMonth: int(currentTime.Month()), CurrentYear: currentTime.Year(),
CurrentDay: currentTime.Day(), CurrentMonth: int(currentTime.Month()),
CurrentHour: currentTime.Hour(), CurrentDay: currentTime.Day(),
CurrentMinute: currentTime.Minute(), CurrentHour: currentTime.Hour(),
CurrentSecond: currentTime.Second(), CurrentMinute: currentTime.Minute(),
Tags: strings.Join(release.Tags, ", "), CurrentSecond: currentTime.Second(),
Artists: release.Artists, Tags: strings.Join(release.Tags, ", "),
Artists: release.Artists,
} }
return ma return ma

View file

@ -36,7 +36,7 @@ func TestMacros_Parse(t *testing.T) {
release: Release{ release: Release{
TorrentName: "This movie 2021", TorrentName: "This movie 2021",
TorrentTmpFile: "/tmp/a-temporary-file.torrent", TorrentTmpFile: "/tmp/a-temporary-file.torrent",
Indexer: IndexerMinimal{0, "Mock Indexer", "mock1"}, Indexer: IndexerMinimal{0, "Mock Indexer", "mock1", "Mock Indexer"},
}, },
args: args{text: "Print mee {{.TorrentPathName}}"}, args: args{text: "Print mee {{.TorrentPathName}}"},
want: "Print mee /tmp/a-temporary-file.torrent", want: "Print mee /tmp/a-temporary-file.torrent",
@ -47,7 +47,7 @@ func TestMacros_Parse(t *testing.T) {
release: Release{ release: Release{
TorrentName: "This movie 2021", TorrentName: "This movie 2021",
TorrentTmpFile: "/tmp/a-temporary-file.torrent", TorrentTmpFile: "/tmp/a-temporary-file.torrent",
Indexer: IndexerMinimal{0, "Mock Indexer", "mock1"}, Indexer: IndexerMinimal{0, "Mock Indexer", "mock1", "Mock Indexer"},
}, },
args: args{text: "Print mee {{TorrentPathName}}"}, args: args{text: "Print mee {{TorrentPathName}}"},
want: "", want: "",
@ -58,7 +58,7 @@ func TestMacros_Parse(t *testing.T) {
release: Release{ release: Release{
TorrentName: "This movie 2021", TorrentName: "This movie 2021",
TorrentTmpFile: "/tmp/a-temporary-file.torrent", TorrentTmpFile: "/tmp/a-temporary-file.torrent",
Indexer: IndexerMinimal{0, "Mock Indexer", "mock1"}, Indexer: IndexerMinimal{0, "Mock Indexer", "mock1", "Mock Indexer"},
}, },
args: args{text: "add {{.TorrentPathName}} --category test"}, args: args{text: "add {{.TorrentPathName}} --category test"},
want: "add /tmp/a-temporary-file.torrent --category test", want: "add /tmp/a-temporary-file.torrent --category test",
@ -68,7 +68,7 @@ func TestMacros_Parse(t *testing.T) {
name: "test_program_arg_bad", name: "test_program_arg_bad",
release: Release{ release: Release{
TorrentTmpFile: "/tmp/a-temporary-file.torrent", TorrentTmpFile: "/tmp/a-temporary-file.torrent",
Indexer: IndexerMinimal{0, "Mock Indexer", "mock1"}, Indexer: IndexerMinimal{0, "Mock Indexer", "mock1", "Mock Indexer"},
}, },
args: args{text: "add {{.TorrenttPathName}} --category test"}, args: args{text: "add {{.TorrenttPathName}} --category test"},
want: "", want: "",
@ -79,7 +79,7 @@ func TestMacros_Parse(t *testing.T) {
release: Release{ release: Release{
TorrentName: "This movie 2021", TorrentName: "This movie 2021",
TorrentTmpFile: "/tmp/a-temporary-file.torrent", TorrentTmpFile: "/tmp/a-temporary-file.torrent",
Indexer: IndexerMinimal{0, "Mock Indexer", "mock1"}, Indexer: IndexerMinimal{0, "Mock Indexer", "mock1", "Mock Indexer"},
}, },
args: args{text: "add {{.TorrentPathName}} --category test --other {{.TorrentName}}"}, args: args{text: "add {{.TorrentPathName}} --category test --other {{.TorrentName}}"},
want: "add /tmp/a-temporary-file.torrent --category test --other This movie 2021", want: "add /tmp/a-temporary-file.torrent --category test --other This movie 2021",
@ -90,7 +90,7 @@ func TestMacros_Parse(t *testing.T) {
release: Release{ release: Release{
TorrentName: "This movie 2021", TorrentName: "This movie 2021",
DownloadURL: "https://some.site/download/fakeid", DownloadURL: "https://some.site/download/fakeid",
Indexer: IndexerMinimal{0, "Mock Indexer", "mock1"}, Indexer: IndexerMinimal{0, "Mock Indexer", "mock1", "Mock Indexer"},
}, },
args: args{text: "{{.TorrentName}} {{.TorrentUrl}} SOME_LONG_TOKEN"}, args: args{text: "{{.TorrentName}} {{.TorrentUrl}} SOME_LONG_TOKEN"},
want: "This movie 2021 https://some.site/download/fakeid SOME_LONG_TOKEN", want: "This movie 2021 https://some.site/download/fakeid SOME_LONG_TOKEN",
@ -101,7 +101,7 @@ func TestMacros_Parse(t *testing.T) {
release: Release{ release: Release{
TorrentName: "This movie 2021", TorrentName: "This movie 2021",
DownloadURL: "https://some.site/download/fakeid", DownloadURL: "https://some.site/download/fakeid",
Indexer: IndexerMinimal{0, "Mock Indexer", "mock1"}, Indexer: IndexerMinimal{0, "Mock Indexer", "mock1", "Mock Indexer"},
}, },
args: args{text: "{{.Indexer}} {{.TorrentName}} {{.TorrentUrl}} SOME_LONG_TOKEN"}, args: args{text: "{{.Indexer}} {{.TorrentName}} {{.TorrentUrl}} SOME_LONG_TOKEN"},
want: "mock1 This movie 2021 https://some.site/download/fakeid SOME_LONG_TOKEN", want: "mock1 This movie 2021 https://some.site/download/fakeid SOME_LONG_TOKEN",
@ -112,7 +112,7 @@ func TestMacros_Parse(t *testing.T) {
release: Release{ release: Release{
TorrentName: "This movie 2021", TorrentName: "This movie 2021",
DownloadURL: "https://some.site/download/fakeid", DownloadURL: "https://some.site/download/fakeid",
Indexer: IndexerMinimal{0, "Mock Indexer", "mock1"}, Indexer: IndexerMinimal{0, "Mock Indexer", "mock1", "Mock Indexer"},
}, },
args: args{text: "{{.Indexer}}-race"}, args: args{text: "{{.Indexer}}-race"},
want: "mock1-race", want: "mock1-race",
@ -123,7 +123,7 @@ func TestMacros_Parse(t *testing.T) {
release: Release{ release: Release{
TorrentName: "This movie 2021", TorrentName: "This movie 2021",
DownloadURL: "https://some.site/download/fakeid", DownloadURL: "https://some.site/download/fakeid",
Indexer: IndexerMinimal{0, "Mock Indexer", "mock1"}, Indexer: IndexerMinimal{0, "Mock Indexer", "mock1", "Mock Indexer"},
}, },
args: args{text: "{{.Indexer}}-{{.CurrentYear}}-race"}, args: args{text: "{{.Indexer}}-{{.CurrentYear}}-race"},
want: fmt.Sprintf("mock1-%v-race", currentTime.Year()), want: fmt.Sprintf("mock1-%v-race", currentTime.Year()),
@ -134,7 +134,7 @@ func TestMacros_Parse(t *testing.T) {
release: Release{ release: Release{
TorrentName: "This movie 2021", TorrentName: "This movie 2021",
DownloadURL: "https://some.site/download/fakeid", DownloadURL: "https://some.site/download/fakeid",
Indexer: IndexerMinimal{0, "Mock Indexer", "mock1"}, Indexer: IndexerMinimal{0, "Mock Indexer", "mock1", "Mock Indexer"},
Resolution: "2160p", Resolution: "2160p",
HDR: []string{"DV"}, HDR: []string{"DV"},
}, },
@ -147,7 +147,7 @@ func TestMacros_Parse(t *testing.T) {
release: Release{ release: Release{
TorrentName: "This movie 2021", TorrentName: "This movie 2021",
DownloadURL: "https://some.site/download/fakeid", DownloadURL: "https://some.site/download/fakeid",
Indexer: IndexerMinimal{0, "Mock Indexer", "mock1"}, Indexer: IndexerMinimal{0, "Mock Indexer", "mock1", "Mock Indexer"},
Resolution: "2160p", Resolution: "2160p",
HDR: []string{"HDR"}, HDR: []string{"HDR"},
}, },
@ -160,7 +160,7 @@ func TestMacros_Parse(t *testing.T) {
release: Release{ release: Release{
TorrentName: "This movie 2021", TorrentName: "This movie 2021",
DownloadURL: "https://some.site/download/fakeid", DownloadURL: "https://some.site/download/fakeid",
Indexer: IndexerMinimal{0, "Mock Indexer", "mock1"}, Indexer: IndexerMinimal{0, "Mock Indexer", "mock1", "Mock Indexer"},
Resolution: "2160p", Resolution: "2160p",
HDR: []string{"HDR"}, HDR: []string{"HDR"},
Year: 2021, Year: 2021,
@ -220,7 +220,7 @@ func TestMacros_Parse(t *testing.T) {
TorrentName: "This movie 2021", TorrentName: "This movie 2021",
DownloadURL: "https://some.site/download/fakeid", DownloadURL: "https://some.site/download/fakeid",
Group: "thisgrp", Group: "thisgrp",
Indexer: IndexerMinimal{0, "Mock Indexer", "mock1"}, Indexer: IndexerMinimal{0, "Mock Indexer", "mock1", "Mock Indexer"},
Year: 2021, Year: 2021,
}, },
args: args{text: "movies-{{.Group}}"}, args: args{text: "movies-{{.Group}}"},
@ -266,7 +266,7 @@ func TestMacros_Parse(t *testing.T) {
{ {
name: "test_args_indexer", name: "test_args_indexer",
release: Release{ release: Release{
Indexer: IndexerMinimal{0, "Mock Indexer", "mock1"}, Indexer: IndexerMinimal{0, "Mock Indexer", "mock1", "Mock Indexer"},
}, },
args: args{text: "indexer={{.IndexerName}}"}, args: args{text: "indexer={{.IndexerName}}"},
want: fmt.Sprintf("indexer=Mock Indexer"), want: fmt.Sprintf("indexer=Mock Indexer"),

View file

@ -95,7 +95,7 @@ func (j *NewznabJob) process(ctx context.Context) error {
} }
} }
rls := domain.NewRelease(domain.IndexerMinimal{ID: j.Feed.Indexer.ID, Name: j.Feed.Indexer.Name, Identifier: j.Feed.Indexer.Identifier}) rls := domain.NewRelease(domain.IndexerMinimal{ID: j.Feed.Indexer.ID, Name: j.Feed.Indexer.Name, Identifier: j.Feed.Indexer.Identifier, IdentifierExternal: j.Feed.Indexer.IdentifierExternal})
rls.Implementation = domain.ReleaseImplementationNewznab rls.Implementation = domain.ReleaseImplementationNewznab
rls.Protocol = domain.ReleaseProtocolNzb rls.Protocol = domain.ReleaseProtocolNzb

View file

@ -119,7 +119,7 @@ func (j *RSSJob) processItem(item *gofeed.Item) *domain.Release {
} }
} }
rls := domain.NewRelease(domain.IndexerMinimal{ID: j.Feed.Indexer.ID, Name: j.Feed.Indexer.Name, Identifier: j.Feed.Indexer.Identifier}) rls := domain.NewRelease(domain.IndexerMinimal{ID: j.Feed.Indexer.ID, Name: j.Feed.Indexer.Name, Identifier: j.Feed.Indexer.Identifier, IdentifierExternal: j.Feed.Indexer.IdentifierExternal})
rls.Implementation = domain.ReleaseImplementationRSS rls.Implementation = domain.ReleaseImplementationRSS
rls.ParseString(item.Title) rls.ParseString(item.Title)

View file

@ -46,9 +46,10 @@ func TestRSSJob_processItem(t *testing.T) {
Feed: &domain.Feed{ Feed: &domain.Feed{
MaxAge: 3600, MaxAge: 3600,
Indexer: domain.IndexerMinimal{ Indexer: domain.IndexerMinimal{
ID: 0, ID: 0,
Name: "Mock Feed", Name: "Mock Feed",
Identifier: "mock-feed", Identifier: "mock-feed",
IdentifierExternal: "Mock Indexer",
}, },
}, },
Name: "test feed", Name: "test feed",
@ -71,7 +72,7 @@ func TestRSSJob_processItem(t *testing.T) {
Link: "/details.php?id=00000&hit=1", Link: "/details.php?id=00000&hit=1",
GUID: "Some.Release.Title.2022.09.22.720p.WEB.h264-GROUP", GUID: "Some.Release.Title.2022.09.22.720p.WEB.h264-GROUP",
}}, }},
want: &domain.Release{ID: 0, FilterStatus: "PENDING", Rejections: []string{}, Indexer: domain.IndexerMinimal{0, "Mock Feed", "mock-feed"}, FilterName: "", Protocol: "torrent", Implementation: "RSS", Timestamp: now, GroupID: "", TorrentID: "", DownloadURL: "https://fake-feed.com/details.php?id=00000&hit=1", TorrentTmpFile: "", TorrentDataRawBytes: []uint8(nil), TorrentHash: "", TorrentName: "Some.Release.Title.2022.09.22.720p.WEB.h264-GROUP", Size: 1490000000, Title: "Some Release Title", Description: "Category: Example\n Size: 1.49 GB\n Status: 27 seeders and 1 leechers\n Speed: 772.16 kB/s\n Added: 2022-09-29 16:06:08\n", Category: "", Season: 0, Episode: 0, Year: 2022, Resolution: "720p", Source: "WEB", Codec: []string{"H.264"}, Container: "", HDR: []string(nil), Audio: []string(nil), AudioChannels: "", Group: "GROUP", Region: "", Language: nil, Proper: false, Repack: false, Website: "", Artists: "", Type: "episode", LogScore: 0, Origin: "", Tags: []string{}, ReleaseTags: "", Freeleech: false, FreeleechPercent: 0, Bonus: []string(nil), Uploader: "", PreTime: "", Other: []string(nil), RawCookie: "", AdditionalSizeCheckRequired: false, FilterID: 0, Filter: (*domain.Filter)(nil), ActionStatus: []domain.ReleaseActionStatus(nil)}, want: &domain.Release{ID: 0, FilterStatus: "PENDING", Rejections: []string{}, Indexer: domain.IndexerMinimal{0, "Mock Feed", "mock-feed", "Mock Indexer"}, FilterName: "", Protocol: "torrent", Implementation: "RSS", Timestamp: now, GroupID: "", TorrentID: "", DownloadURL: "https://fake-feed.com/details.php?id=00000&hit=1", TorrentTmpFile: "", TorrentDataRawBytes: []uint8(nil), TorrentHash: "", TorrentName: "Some.Release.Title.2022.09.22.720p.WEB.h264-GROUP", Size: 1490000000, Title: "Some Release Title", Description: "Category: Example\n Size: 1.49 GB\n Status: 27 seeders and 1 leechers\n Speed: 772.16 kB/s\n Added: 2022-09-29 16:06:08\n", Category: "", Season: 0, Episode: 0, Year: 2022, Resolution: "720p", Source: "WEB", Codec: []string{"H.264"}, Container: "", HDR: []string(nil), Audio: []string(nil), AudioChannels: "", Group: "GROUP", Region: "", Language: nil, Proper: false, Repack: false, Website: "", Artists: "", Type: "episode", LogScore: 0, Origin: "", Tags: []string{}, ReleaseTags: "", Freeleech: false, FreeleechPercent: 0, Bonus: []string(nil), Uploader: "", PreTime: "", Other: []string(nil), RawCookie: "", AdditionalSizeCheckRequired: false, FilterID: 0, Filter: (*domain.Filter)(nil), ActionStatus: []domain.ReleaseActionStatus(nil)},
}, },
{ {
name: "with_baseurl", name: "with_baseurl",
@ -79,9 +80,10 @@ func TestRSSJob_processItem(t *testing.T) {
Feed: &domain.Feed{ Feed: &domain.Feed{
MaxAge: 3600, MaxAge: 3600,
Indexer: domain.IndexerMinimal{ Indexer: domain.IndexerMinimal{
ID: 0, ID: 0,
Name: "Mock Feed", Name: "Mock Feed",
Identifier: "mock-feed", Identifier: "mock-feed",
IdentifierExternal: "Mock Indexer",
}, },
}, },
Name: "test feed", Name: "test feed",
@ -104,7 +106,7 @@ func TestRSSJob_processItem(t *testing.T) {
Link: "https://fake-feed.com/details.php?id=00000&hit=1", Link: "https://fake-feed.com/details.php?id=00000&hit=1",
GUID: "Some.Release.Title.2022.09.22.720p.WEB.h264-GROUP", GUID: "Some.Release.Title.2022.09.22.720p.WEB.h264-GROUP",
}}, }},
want: &domain.Release{ID: 0, FilterStatus: "PENDING", Rejections: []string{}, Indexer: domain.IndexerMinimal{0, "Mock Feed", "mock-feed"}, FilterName: "", Protocol: "torrent", Implementation: "RSS", Timestamp: now, GroupID: "", TorrentID: "", DownloadURL: "https://fake-feed.com/details.php?id=00000&hit=1", TorrentTmpFile: "", TorrentDataRawBytes: []uint8(nil), TorrentHash: "", TorrentName: "Some.Release.Title.2022.09.22.720p.WEB.h264-GROUP", Size: 1490000000, Title: "Some Release Title", Description: "Category: Example\n Size: 1.49 GB\n Status: 27 seeders and 1 leechers\n Speed: 772.16 kB/s\n Added: 2022-09-29 16:06:08\n", Category: "", Season: 0, Episode: 0, Year: 2022, Resolution: "720p", Source: "WEB", Codec: []string{"H.264"}, Container: "", HDR: []string(nil), Audio: []string(nil), AudioChannels: "", Group: "GROUP", Region: "", Language: nil, Proper: false, Repack: false, Website: "", Artists: "", Type: "episode", LogScore: 0, Origin: "", Tags: []string{}, ReleaseTags: "", Freeleech: false, FreeleechPercent: 0, Bonus: []string(nil), Uploader: "", PreTime: "", Other: []string(nil), RawCookie: "", AdditionalSizeCheckRequired: false, FilterID: 0, Filter: (*domain.Filter)(nil), ActionStatus: []domain.ReleaseActionStatus(nil)}, want: &domain.Release{ID: 0, FilterStatus: "PENDING", Rejections: []string{}, Indexer: domain.IndexerMinimal{0, "Mock Feed", "mock-feed", "Mock Indexer"}, FilterName: "", Protocol: "torrent", Implementation: "RSS", Timestamp: now, GroupID: "", TorrentID: "", DownloadURL: "https://fake-feed.com/details.php?id=00000&hit=1", TorrentTmpFile: "", TorrentDataRawBytes: []uint8(nil), TorrentHash: "", TorrentName: "Some.Release.Title.2022.09.22.720p.WEB.h264-GROUP", Size: 1490000000, Title: "Some Release Title", Description: "Category: Example\n Size: 1.49 GB\n Status: 27 seeders and 1 leechers\n Speed: 772.16 kB/s\n Added: 2022-09-29 16:06:08\n", Category: "", Season: 0, Episode: 0, Year: 2022, Resolution: "720p", Source: "WEB", Codec: []string{"H.264"}, Container: "", HDR: []string(nil), Audio: []string(nil), AudioChannels: "", Group: "GROUP", Region: "", Language: nil, Proper: false, Repack: false, Website: "", Artists: "", Type: "episode", LogScore: 0, Origin: "", Tags: []string{}, ReleaseTags: "", Freeleech: false, FreeleechPercent: 0, Bonus: []string(nil), Uploader: "", PreTime: "", Other: []string(nil), RawCookie: "", AdditionalSizeCheckRequired: false, FilterID: 0, Filter: (*domain.Filter)(nil), ActionStatus: []domain.ReleaseActionStatus(nil)},
}, },
{ {
name: "time_parse", name: "time_parse",
@ -112,9 +114,10 @@ func TestRSSJob_processItem(t *testing.T) {
Feed: &domain.Feed{ Feed: &domain.Feed{
MaxAge: 360, MaxAge: 360,
Indexer: domain.IndexerMinimal{ Indexer: domain.IndexerMinimal{
ID: 0, ID: 0,
Name: "Mock Feed", Name: "Mock Feed",
Identifier: "mock-feed", Identifier: "mock-feed",
IdentifierExternal: "Mock Indexer",
}, },
}, },
Name: "test feed", Name: "test feed",
@ -138,7 +141,7 @@ func TestRSSJob_processItem(t *testing.T) {
GUID: "Some.Release.Title.2022.09.22.720p.WEB.h264-GROUP", GUID: "Some.Release.Title.2022.09.22.720p.WEB.h264-GROUP",
//PublishedParsed: &nowMinusTime, //PublishedParsed: &nowMinusTime,
}}, }},
want: &domain.Release{ID: 0, FilterStatus: "PENDING", Rejections: []string{}, Indexer: domain.IndexerMinimal{0, "Mock Feed", "mock-feed"}, FilterName: "", Protocol: "torrent", Implementation: "RSS", Timestamp: now, GroupID: "", TorrentID: "", DownloadURL: "https://fake-feed.com/details.php?id=00000&hit=1", TorrentTmpFile: "", TorrentDataRawBytes: []uint8(nil), TorrentHash: "", TorrentName: "Some.Release.Title.2022.09.22.720p.WEB.h264-GROUP", Size: 1490000000, Title: "Some Release Title", Description: "Category: Example\n Size: 1.49 GB\n Status: 27 seeders and 1 leechers\n Speed: 772.16 kB/s\n Added: 2022-09-29 16:06:08\n", Category: "", Season: 0, Episode: 0, Year: 2022, Resolution: "720p", Source: "WEB", Codec: []string{"H.264"}, Container: "", HDR: []string(nil), Audio: []string(nil), AudioChannels: "", Group: "GROUP", Region: "", Language: nil, Proper: false, Repack: false, Website: "", Artists: "", Type: "episode", LogScore: 0, Origin: "", Tags: []string{}, ReleaseTags: "", Freeleech: false, FreeleechPercent: 0, Bonus: []string(nil), Uploader: "", PreTime: "", Other: []string(nil), RawCookie: "", AdditionalSizeCheckRequired: false, FilterID: 0, Filter: (*domain.Filter)(nil), ActionStatus: []domain.ReleaseActionStatus(nil)}, want: &domain.Release{ID: 0, FilterStatus: "PENDING", Rejections: []string{}, Indexer: domain.IndexerMinimal{0, "Mock Feed", "mock-feed", "Mock Indexer"}, FilterName: "", Protocol: "torrent", Implementation: "RSS", Timestamp: now, GroupID: "", TorrentID: "", DownloadURL: "https://fake-feed.com/details.php?id=00000&hit=1", TorrentTmpFile: "", TorrentDataRawBytes: []uint8(nil), TorrentHash: "", TorrentName: "Some.Release.Title.2022.09.22.720p.WEB.h264-GROUP", Size: 1490000000, Title: "Some Release Title", Description: "Category: Example\n Size: 1.49 GB\n Status: 27 seeders and 1 leechers\n Speed: 772.16 kB/s\n Added: 2022-09-29 16:06:08\n", Category: "", Season: 0, Episode: 0, Year: 2022, Resolution: "720p", Source: "WEB", Codec: []string{"H.264"}, Container: "", HDR: []string(nil), Audio: []string(nil), AudioChannels: "", Group: "GROUP", Region: "", Language: nil, Proper: false, Repack: false, Website: "", Artists: "", Type: "episode", LogScore: 0, Origin: "", Tags: []string{}, ReleaseTags: "", Freeleech: false, FreeleechPercent: 0, Bonus: []string(nil), Uploader: "", PreTime: "", Other: []string(nil), RawCookie: "", AdditionalSizeCheckRequired: false, FilterID: 0, Filter: (*domain.Filter)(nil), ActionStatus: []domain.ReleaseActionStatus(nil)},
}, },
{ {
name: "time_parse", name: "time_parse",
@ -175,9 +178,10 @@ func TestRSSJob_processItem(t *testing.T) {
Feed: &domain.Feed{ Feed: &domain.Feed{
MaxAge: 3600, MaxAge: 3600,
Indexer: domain.IndexerMinimal{ Indexer: domain.IndexerMinimal{
ID: 0, ID: 0,
Name: "Mock Feed", Name: "Mock Feed",
Identifier: "mock-feed", Identifier: "mock-feed",
IdentifierExternal: "Mock Indexer",
}, },
Settings: &domain.FeedSettingsJSON{DownloadType: domain.FeedDownloadTypeMagnet}, Settings: &domain.FeedSettingsJSON{DownloadType: domain.FeedDownloadTypeMagnet},
}, },
@ -203,7 +207,7 @@ func TestRSSJob_processItem(t *testing.T) {
}, },
}, },
}}, }},
want: &domain.Release{ID: 0, FilterStatus: "PENDING", Rejections: []string{}, Indexer: domain.IndexerMinimal{0, "Mock Feed", "mock-feed"}, FilterName: "", Protocol: "torrent", Implementation: "RSS", Timestamp: now, MagnetURI: "magnet:?xt=this-not-a-valid-magnet", GroupID: "", TorrentID: "", DownloadURL: "https://fake-feed.com/details.php?id=00000&hit=1", TorrentTmpFile: "", TorrentDataRawBytes: []uint8(nil), TorrentHash: "", TorrentName: "Some.Release.Title.2022.09.22.720p.WEB.h264-GROUP", Size: 0, Title: "Some Release Title", Description: "Category: Example", Category: "", Season: 0, Episode: 0, Year: 2022, Resolution: "720p", Source: "WEB", Codec: []string{"H.264"}, Container: "", HDR: []string(nil), Audio: []string(nil), AudioChannels: "", Group: "GROUP", Region: "", Language: nil, Proper: false, Repack: false, Website: "", Artists: "", Type: "episode", LogScore: 0, Origin: "", Tags: []string{}, ReleaseTags: "", Freeleech: false, FreeleechPercent: 0, Bonus: []string(nil), Uploader: "", PreTime: "", Other: []string(nil), RawCookie: "", AdditionalSizeCheckRequired: false, FilterID: 0, Filter: (*domain.Filter)(nil), ActionStatus: []domain.ReleaseActionStatus(nil)}, want: &domain.Release{ID: 0, FilterStatus: "PENDING", Rejections: []string{}, Indexer: domain.IndexerMinimal{0, "Mock Feed", "mock-feed", "Mock Indexer"}, FilterName: "", Protocol: "torrent", Implementation: "RSS", Timestamp: now, MagnetURI: "magnet:?xt=this-not-a-valid-magnet", GroupID: "", TorrentID: "", DownloadURL: "https://fake-feed.com/details.php?id=00000&hit=1", TorrentTmpFile: "", TorrentDataRawBytes: []uint8(nil), TorrentHash: "", TorrentName: "Some.Release.Title.2022.09.22.720p.WEB.h264-GROUP", Size: 0, Title: "Some Release Title", Description: "Category: Example", Category: "", Season: 0, Episode: 0, Year: 2022, Resolution: "720p", Source: "WEB", Codec: []string{"H.264"}, Container: "", HDR: []string(nil), Audio: []string(nil), AudioChannels: "", Group: "GROUP", Region: "", Language: nil, Proper: false, Repack: false, Website: "", Artists: "", Type: "episode", LogScore: 0, Origin: "", Tags: []string{}, ReleaseTags: "", Freeleech: false, FreeleechPercent: 0, Bonus: []string(nil), Uploader: "", PreTime: "", Other: []string(nil), RawCookie: "", AdditionalSizeCheckRequired: false, FilterID: 0, Filter: (*domain.Filter)(nil), ActionStatus: []domain.ReleaseActionStatus(nil)},
}, },
} }
for _, tt := range tests { for _, tt := range tests {

View file

@ -101,7 +101,7 @@ func (j *TorznabJob) process(ctx context.Context) error {
} }
} }
rls := domain.NewRelease(domain.IndexerMinimal{ID: j.Feed.Indexer.ID, Name: j.Feed.Indexer.Name, Identifier: j.Feed.Indexer.Identifier}) rls := domain.NewRelease(domain.IndexerMinimal{ID: j.Feed.Indexer.ID, Name: j.Feed.Indexer.Name, Identifier: j.Feed.Indexer.Identifier, IdentifierExternal: j.Feed.Indexer.IdentifierExternal})
rls.Implementation = domain.ReleaseImplementationTorznab rls.Implementation = domain.ReleaseImplementationTorznab
rls.TorrentName = item.Title rls.TorrentName = item.Title

View file

@ -15,8 +15,9 @@ import (
func TestIndexersParseAndFilter(t *testing.T) { func TestIndexersParseAndFilter(t *testing.T) {
type fields struct { type fields struct {
identifier string identifier string
settings map[string]string identifierExternal string
settings map[string]string
} }
type filterTest struct { type filterTest struct {
filter *domain.Filter filter *domain.Filter
@ -41,7 +42,8 @@ func TestIndexersParseAndFilter(t *testing.T) {
{ {
name: "ops", name: "ops",
fields: fields{ fields: fields{
identifier: "orpheus", identifier: "orpheus",
identifierExternal: "Orpheus",
settings: map[string]string{ settings: map[string]string{
"torrent_pass": "pass", "torrent_pass": "pass",
"api_key": "key", "api_key": "key",
@ -115,7 +117,8 @@ func TestIndexersParseAndFilter(t *testing.T) {
{ {
name: "redacted", name: "redacted",
fields: fields{ fields: fields{
identifier: "red", identifier: "red",
identifierExternal: "Redacted",
settings: map[string]string{ settings: map[string]string{
"authkey": "key", "authkey": "key",
"torrent_pass": "pass", "torrent_pass": "pass",
@ -298,6 +301,7 @@ func TestIndexersParseAndFilter(t *testing.T) {
i, err := OpenAndProcessDefinition("./definitions/" + tt.fields.identifier + ".yaml") i, err := OpenAndProcessDefinition("./definitions/" + tt.fields.identifier + ".yaml")
assert.NoError(t, err) assert.NoError(t, err)
i.IdentifierExternal = tt.fields.identifierExternal
i.SettingsMap = tt.fields.settings i.SettingsMap = tt.fields.settings
ll := zerolog.New(io.Discard) ll := zerolog.New(io.Discard)
@ -327,7 +331,7 @@ func TestIndexersParseAndFilter(t *testing.T) {
return return
} }
rls := domain.NewRelease(domain.IndexerMinimal{ID: i.ID, Name: i.Name, Identifier: i.Identifier}) rls := domain.NewRelease(domain.IndexerMinimal{ID: i.ID, Name: i.Name, Identifier: i.Identifier, IdentifierExternal: i.IdentifierExternal})
rls.Protocol = domain.ReleaseProtocol(i.Protocol) rls.Protocol = domain.ReleaseProtocol(i.Protocol)
// on lines matched // on lines matched

View file

@ -275,6 +275,7 @@ func (s *service) mapIndexer(indexer domain.Indexer) (*domain.IndexerDefinition,
d.ID = int(indexer.ID) d.ID = int(indexer.ID)
d.Name = indexer.Name d.Name = indexer.Name
d.Identifier = indexer.Identifier d.Identifier = indexer.Identifier
d.IdentifierExternal = indexer.IdentifierExternal
d.Implementation = indexer.Implementation d.Implementation = indexer.Implementation
d.BaseURL = indexer.BaseURL d.BaseURL = indexer.BaseURL
d.Enabled = indexer.Enabled d.Enabled = indexer.Enabled
@ -311,6 +312,7 @@ func (s *service) updateMapIndexer(indexer domain.Indexer) (*domain.IndexerDefin
d.ID = int(indexer.ID) d.ID = int(indexer.ID)
d.Name = indexer.Name d.Name = indexer.Name
d.Identifier = indexer.Identifier d.Identifier = indexer.Identifier
d.IdentifierExternal = indexer.IdentifierExternal
d.Implementation = indexer.Implementation d.Implementation = indexer.Implementation
d.BaseURL = indexer.BaseURL d.BaseURL = indexer.BaseURL
d.Enabled = indexer.Enabled d.Enabled = indexer.Enabled

View file

@ -101,7 +101,7 @@ func (s *service) ProcessManual(ctx context.Context, req *domain.ReleaseProcessR
return err return err
} }
rls := domain.NewRelease(domain.IndexerMinimal{ID: def.ID, Name: def.Name, Identifier: def.Identifier}) rls := domain.NewRelease(domain.IndexerMinimal{ID: def.ID, Name: def.Name, Identifier: def.Identifier, IdentifierExternal: def.IdentifierExternal})
switch req.IndexerImplementation { switch req.IndexerImplementation {
case string(domain.IndexerImplementationIRC): case string(domain.IndexerImplementationIRC):

View file

@ -718,6 +718,7 @@ interface IndexerUpdateInitialValues {
name: string; name: string;
enabled: boolean; enabled: boolean;
identifier: string; identifier: string;
identifier_external: string;
implementation: string; implementation: string;
base_url: string; base_url: string;
settings: { settings: {
@ -812,6 +813,7 @@ export function IndexerUpdateForm({ isOpen, toggle, indexer }: UpdateProps) {
name: indexer.name, name: indexer.name,
enabled: indexer.enabled || false, enabled: indexer.enabled || false,
identifier: indexer.identifier, identifier: indexer.identifier,
identifier_external: indexer.identifier_external,
implementation: indexer.implementation, implementation: indexer.implementation,
base_url: indexer.base_url, base_url: indexer.base_url,
settings: indexer.settings?.reduce( settings: indexer.settings?.reduce(
@ -856,6 +858,21 @@ export function IndexerUpdateForm({ isOpen, toggle, indexer }: UpdateProps) {
)} )}
</Field> </Field>
</div> </div>
<TextFieldWide
name="identifier_external"
label="External Identifier"
help={`External Identifier for ARRs. If using Prowlarr set like: ${indexer.name} (Prowlarr)`}
tooltip={
<div>
<p>External Identifier for use with ARRs to get features like seed limits working.</p>
<br />
<p>This needs to match the indexer name in your ARR. If using Prowlarr it will likely be "{indexer.name} (Prowlarr)"</p>
<br />
<DocsLink href="https://autobrr.com/configuration/indexers#setup" />
</div>
}
/>
<SwitchGroupWide name="enabled" label="Enabled" /> <SwitchGroupWide name="enabled" label="Enabled" />
{indexer.implementation == "irc" && ( {indexer.implementation == "irc" && (

View file

@ -243,6 +243,7 @@ export const ActivityTable = () => {
id: 0, id: 0,
name: index % 2 === 0 ? "distrowatch" : "linuxtracker", name: index % 2 === 0 ? "distrowatch" : "linuxtracker",
identifier: index % 2 === 0 ? "distrowatch" : "linuxtracker", identifier: index % 2 === 0 ? "distrowatch" : "linuxtracker",
identifier_external: index % 2 === 0 ? "distrowatch" : "linuxtracker",
}, },
})); }));
setModifiedData(newData); setModifiedData(newData);
@ -323,6 +324,7 @@ export const ActivityTableContent = () => {
id: 0, id: 0,
name: index % 2 === 0 ? "distrowatch" : "linuxtracker", name: index % 2 === 0 ? "distrowatch" : "linuxtracker",
identifier: index % 2 === 0 ? "distrowatch" : "linuxtracker", identifier: index % 2 === 0 ? "distrowatch" : "linuxtracker",
identifier_external: index % 2 === 0 ? "distrowatch" : "linuxtracker",
}, },
})); }));
setModifiedData(newData); setModifiedData(newData);

View file

@ -152,6 +152,7 @@ export const ReleaseTable = () => {
id: 0, id: 0,
name: index % 2 === 0 ? "distrowatch" : "linuxtracker", name: index % 2 === 0 ? "distrowatch" : "linuxtracker",
identifier: index % 2 === 0 ? "distrowatch" : "linuxtracker", identifier: index % 2 === 0 ? "distrowatch" : "linuxtracker",
identifier_external: index % 2 === 0 ? "distrowatch" : "linuxtracker",
}, },
category: "Linux ISOs", category: "Linux ISOs",
size: index % 2 === 0 ? 4566784529 : (index % 3 === 0 ? 7427019812 : 2312122455), size: index % 2 === 0 ? 4566784529 : (index % 3 === 0 ? 7427019812 : 2312122455),

View file

@ -7,6 +7,7 @@ interface Indexer {
id: number; id: number;
name: string; name: string;
identifier: string; identifier: string;
identifier_external: string;
enabled: boolean; enabled: boolean;
implementation: string; implementation: string;
base_url: string; base_url: string;
@ -17,12 +18,14 @@ interface IndexerMinimal {
id: number; id: number;
name: string; name: string;
identifier: string; identifier: string;
identifier_external: string;
} }
interface IndexerDefinition { interface IndexerDefinition {
id: number; id: number;
name: string; name: string;
identifier: string; identifier: string;
identifier_external: string;
implementation: string; implementation: string;
base_url: string; base_url: string;
enabled?: boolean; enabled?: boolean;