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

@ -85,6 +85,7 @@ func Test_service_execCmd(t *testing.T) {
ID: 0,
Name: "Mock Indexer",
Identifier: "mock",
IdentifierExternal: "Mock Indexer",
},
},
action: &domain.Action{

View file

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

View file

@ -103,7 +103,7 @@ func (a *announceProcessor) processQueue(queue chan string) {
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)
// on lines matched

View file

@ -34,6 +34,7 @@ func (r *FeedRepo) FindByID(ctx context.Context, id int) (*domain.Feed, error) {
"f.id",
"i.id",
"i.identifier",
"i.identifier_external",
"i.name",
"f.name",
"f.type",
@ -66,7 +67,7 @@ func (r *FeedRepo) FindByID(ctx context.Context, id int) (*domain.Feed, error) {
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")
}
@ -91,6 +92,7 @@ func (r *FeedRepo) FindByIndexerIdentifier(ctx context.Context, indexer string)
"f.id",
"i.id",
"i.identifier",
"i.identifier_external",
"i.name",
"f.name",
"f.type",
@ -123,7 +125,7 @@ func (r *FeedRepo) FindByIndexerIdentifier(ctx context.Context, indexer string)
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")
}
@ -146,6 +148,7 @@ func (r *FeedRepo) Find(ctx context.Context) ([]domain.Feed, error) {
"f.id",
"i.id",
"i.identifier",
"i.identifier_external",
"i.name",
"f.name",
"f.type",
@ -185,7 +188,7 @@ func (r *FeedRepo) Find(ctx context.Context) ([]domain.Feed, error) {
var apiKey, cookie, lastRunData, settings sql.NullString
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")
}

View file

@ -36,19 +36,16 @@ func (r *IndexerRepo) Store(ctx context.Context, indexer domain.Indexer) (*domai
}
queryBuilder := r.db.squirrel.
Insert("indexer").Columns("enabled", "name", "identifier", "implementation", "base_url", "settings").
Values(indexer.Enabled, indexer.Name, indexer.Identifier, indexer.Implementation, indexer.BaseURL, settings).
Insert("indexer").Columns("enabled", "name", "identifier", "identifier_external", "implementation", "base_url", "settings").
Values(indexer.Enabled, indexer.Name, indexer.Identifier, indexer.IdentifierExternal, indexer.Implementation, indexer.BaseURL, settings).
Suffix("RETURNING id").RunWith(r.db.handler)
// return values
var retID int64
if err = queryBuilder.QueryRowContext(ctx).Scan(&retID); err != nil {
err = queryBuilder.QueryRowContext(ctx).Scan(&indexer.ID)
if err != nil {
return nil, errors.Wrap(err, "error executing query")
}
indexer.ID = retID
return &indexer, nil
}
@ -62,6 +59,7 @@ func (r *IndexerRepo) Update(ctx context.Context, indexer domain.Indexer) (*doma
Update("indexer").
Set("enabled", indexer.Enabled).
Set("name", indexer.Name).
Set("identifier_external", indexer.IdentifierExternal).
Set("base_url", indexer.BaseURL).
Set("settings", settings).
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) {
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").
OrderBy("name ASC")
@ -102,16 +100,17 @@ func (r *IndexerRepo) List(ctx context.Context) ([]domain.Indexer, error) {
for rows.Next() {
var f domain.Indexer
var implementation, baseURL sql.NullString
var identifierExternal, implementation, baseURL sql.Null[string]
var settings 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")
}
f.Implementation = implementation.String
f.BaseURL = baseURL.String
f.IdentifierExternal = identifierExternal.V
f.Implementation = implementation.V
f.BaseURL = baseURL.V
if err = json.Unmarshal([]byte(settings), &settingsMap); err != nil {
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) {
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").
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 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")
}
i.Implementation = implementation.String
i.BaseURL = baseURL.String
i.IdentifierExternal = identifierExternal.V
i.Implementation = implementation.V
i.BaseURL = baseURL.V
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")
}
@ -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) {
queryBuilder := r.db.squirrel.
Select("id", "enabled", "name", "identifier", "base_url", "settings").
Select("id", "enabled", "name", "identifier", "identifier_external", "base_url", "settings").
From("indexer").
Join("filter_indexer ON indexer.id = filter_indexer.indexer_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 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")
}
@ -200,7 +200,8 @@ func (r *IndexerRepo) FindByFilterID(ctx context.Context, id int) ([]domain.Inde
return nil, errors.Wrap(err, "error unmarshal settings")
}
f.BaseURL = baseURL.String
f.IdentifierExternal = identifierExternal.V
f.BaseURL = baseURL.V
f.Settings = settingsMap
indexers = append(indexers, f)

View file

@ -18,6 +18,7 @@ CREATE TABLE indexer
(
id SERIAL PRIMARY KEY,
identifier TEXT,
identifier_external TEXT,
implementation TEXT,
base_url TEXT,
enabled BOOLEAN,
@ -877,5 +878,11 @@ ALTER TABLE filter
`,
`ALTER TABLE action
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

@ -18,6 +18,7 @@ CREATE TABLE indexer
(
id INTEGER PRIMARY KEY,
identifier TEXT,
identifier_external TEXT,
implementation TEXT,
base_url TEXT,
enabled BOOLEAN,
@ -1515,5 +1516,11 @@ ALTER TABLE filter
`,
`ALTER TABLE action
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

@ -29,6 +29,7 @@ type Indexer struct {
ID int64 `json:"id"`
Name string `json:"name"`
Identifier string `json:"identifier"`
IdentifierExternal string `json:"identifier_external"`
Enabled bool `json:"enabled"`
Implementation string `json:"implementation"`
BaseURL string `json:"base_url,omitempty"`
@ -39,12 +40,14 @@ type IndexerMinimal struct {
ID int `json:"id"`
Name string `json:"name"`
Identifier string `json:"identifier"`
IdentifierExternal string `json:"identifier_external"`
}
type IndexerDefinition struct {
ID int `json:"id,omitempty"`
Name string `json:"name"`
Identifier string `json:"identifier"`
IdentifierExternal string `json:"identifier_external"`
Implementation string `json:"implementation"`
BaseURL string `json:"base_url,omitempty"`
Enabled bool `json:"enabled"`

View file

@ -254,7 +254,7 @@ func TestIRCParserGazelleGames_Parse(t *testing.T) {
{
name: "",
args: args{
rls: NewRelease(IndexerMinimal{0, "GazelleGames", "ggn"}),
rls: NewRelease(IndexerMinimal{0, "GazelleGames", "ggn", "GazelleGames"}),
vars: map[string]string{
"torrentName": "Trouble.in.Paradise-GROUP in Trouble in Paradise",
},
@ -267,7 +267,7 @@ func TestIRCParserGazelleGames_Parse(t *testing.T) {
{
name: "",
args: args{
rls: NewRelease(IndexerMinimal{0, "GazelleGames", "ggn"}),
rls: NewRelease(IndexerMinimal{0, "GazelleGames", "ggn", "GazelleGames"}),
vars: map[string]string{
"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: "",
args: args{
rls: NewRelease(IndexerMinimal{0, "GazelleGames", "ggn"}),
rls: NewRelease(IndexerMinimal{0, "GazelleGames", "ggn", "GazelleGames"}),
vars: map[string]string{
"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: "",
args: args{
rls: NewRelease(IndexerMinimal{0, "GazelleGames", "ggn"}),
rls: NewRelease(IndexerMinimal{0, "GazelleGames", "ggn", "GazelleGames"}),
vars: map[string]string{
"torrentName": "Year 2 Remastered by Insaneintherainmusic",
"category": "OST",
@ -332,7 +332,7 @@ func TestIRCParserOrpheus_Parse(t *testing.T) {
{
name: "",
args: args{
rls: NewRelease(IndexerMinimal{0, "Orpheus", "ops"}),
rls: NewRelease(IndexerMinimal{0, "Orpheus", "ops", "Orpheus"}),
vars: map[string]string{
"torrentName": "Busta Rhymes BEACH BALL (feat. BIA) [2023] [Single] WEB/FLAC/24bit Lossless",
"title": "Busta Rhymes BEACH BALL (feat. BIA)",
@ -348,7 +348,7 @@ func TestIRCParserOrpheus_Parse(t *testing.T) {
{
name: "",
args: args{
rls: NewRelease(IndexerMinimal{0, "Orpheus", "ops"}),
rls: NewRelease(IndexerMinimal{0, "Orpheus", "ops", "Orpheus"}),
vars: map[string]string{
"torrentName": "Busta Rhymes BEACH BALL (feat. BIA) [2023] [Single] CD/FLAC/Lossless",
"title": "Busta Rhymes BEACH BALL (feat. BIA)",

View file

@ -30,6 +30,7 @@ type Macro struct {
Indexer string
IndexerName string
IndexerIdentifier string
IndexerIdentifierExternal string
Title string
Type string
Category string
@ -72,6 +73,7 @@ func NewMacro(release Release) Macro {
Indexer: release.Indexer.Identifier,
IndexerName: release.Indexer.Name,
IndexerIdentifier: release.Indexer.Identifier,
IndexerIdentifierExternal: release.Indexer.IdentifierExternal,
Title: release.Title,
Type: release.Type,
Category: release.Category,

View file

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

View file

@ -49,6 +49,7 @@ func TestRSSJob_processItem(t *testing.T) {
ID: 0,
Name: "Mock Feed",
Identifier: "mock-feed",
IdentifierExternal: "Mock Indexer",
},
},
Name: "test feed",
@ -71,7 +72,7 @@ func TestRSSJob_processItem(t *testing.T) {
Link: "/details.php?id=00000&hit=1",
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",
@ -82,6 +83,7 @@ func TestRSSJob_processItem(t *testing.T) {
ID: 0,
Name: "Mock Feed",
Identifier: "mock-feed",
IdentifierExternal: "Mock Indexer",
},
},
Name: "test feed",
@ -104,7 +106,7 @@ func TestRSSJob_processItem(t *testing.T) {
Link: "https://fake-feed.com/details.php?id=00000&hit=1",
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",
@ -115,6 +117,7 @@ func TestRSSJob_processItem(t *testing.T) {
ID: 0,
Name: "Mock Feed",
Identifier: "mock-feed",
IdentifierExternal: "Mock Indexer",
},
},
Name: "test feed",
@ -138,7 +141,7 @@ func TestRSSJob_processItem(t *testing.T) {
GUID: "Some.Release.Title.2022.09.22.720p.WEB.h264-GROUP",
//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",
@ -178,6 +181,7 @@ func TestRSSJob_processItem(t *testing.T) {
ID: 0,
Name: "Mock Feed",
Identifier: "mock-feed",
IdentifierExternal: "Mock Indexer",
},
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 {

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.TorrentName = item.Title

View file

@ -16,6 +16,7 @@ import (
func TestIndexersParseAndFilter(t *testing.T) {
type fields struct {
identifier string
identifierExternal string
settings map[string]string
}
type filterTest struct {
@ -42,6 +43,7 @@ func TestIndexersParseAndFilter(t *testing.T) {
name: "ops",
fields: fields{
identifier: "orpheus",
identifierExternal: "Orpheus",
settings: map[string]string{
"torrent_pass": "pass",
"api_key": "key",
@ -116,6 +118,7 @@ func TestIndexersParseAndFilter(t *testing.T) {
name: "redacted",
fields: fields{
identifier: "red",
identifierExternal: "Redacted",
settings: map[string]string{
"authkey": "key",
"torrent_pass": "pass",
@ -298,6 +301,7 @@ func TestIndexersParseAndFilter(t *testing.T) {
i, err := OpenAndProcessDefinition("./definitions/" + tt.fields.identifier + ".yaml")
assert.NoError(t, err)
i.IdentifierExternal = tt.fields.identifierExternal
i.SettingsMap = tt.fields.settings
ll := zerolog.New(io.Discard)
@ -327,7 +331,7 @@ func TestIndexersParseAndFilter(t *testing.T) {
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)
// on lines matched

View file

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

View file

@ -101,7 +101,7 @@ func (s *service) ProcessManual(ctx context.Context, req *domain.ReleaseProcessR
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 {
case string(domain.IndexerImplementationIRC):

View file

@ -718,6 +718,7 @@ interface IndexerUpdateInitialValues {
name: string;
enabled: boolean;
identifier: string;
identifier_external: string;
implementation: string;
base_url: string;
settings: {
@ -812,6 +813,7 @@ export function IndexerUpdateForm({ isOpen, toggle, indexer }: UpdateProps) {
name: indexer.name,
enabled: indexer.enabled || false,
identifier: indexer.identifier,
identifier_external: indexer.identifier_external,
implementation: indexer.implementation,
base_url: indexer.base_url,
settings: indexer.settings?.reduce(
@ -856,6 +858,21 @@ export function IndexerUpdateForm({ isOpen, toggle, indexer }: UpdateProps) {
)}
</Field>
</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" />
{indexer.implementation == "irc" && (

View file

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

View file

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

View file

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