feat(indexers): add support for optional baseurl override (#551)

* feat(indexers): optional baseurl override

* feat(indexers): update baseUrl parsing

* refactor(indexers): BREAKING move parse to IRC struct

* Move Parse as part of IRC struct from Indexer
* Updated definitions
* Build torrentUrl in stages
* Use new url.JoinPath to build torrentUrl
* Update tests

* refactor(indexers): select option obj

* refactor(indexers): make backwards compatible
This commit is contained in:
ze0s 2022-12-03 15:40:45 +01:00 committed by GitHub
parent 301180e55b
commit 25a165b764
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
66 changed files with 1533 additions and 1211 deletions

View file

@ -69,19 +69,19 @@ func (a *announceProcessor) processQueue(queue chan string) {
parseFailed := false parseFailed := false
//patternParsed := false //patternParsed := false
for _, pattern := range a.indexer.Parse.Lines { for _, parseLine := range a.indexer.IRC.Parse.Lines {
line, err := a.getNextLine(queue) line, err := a.getNextLine(queue)
if err != nil { if err != nil {
a.log.Error().Stack().Err(err).Msg("could not get line from queue") a.log.Error().Err(err).Msg("could not get line from queue")
return return
} }
a.log.Trace().Msgf("announce: process line: %v", line) a.log.Trace().Msgf("announce: process line: %v", line)
// check should ignore // check should ignore
match, err := a.parseExtract(pattern.Pattern, pattern.Vars, tmpVars, line) match, err := a.parseLine(parseLine.Pattern, parseLine.Vars, tmpVars, line)
if err != nil { if err != nil {
a.log.Debug().Msgf("error parsing extract: %v", line) a.log.Error().Err(err).Msgf("error parsing extract for line: %v", line)
parseFailed = true parseFailed = true
break break
@ -95,7 +95,6 @@ func (a *announceProcessor) processQueue(queue chan string) {
} }
if parseFailed { if parseFailed {
a.log.Trace().Msg("announce: parse failed")
continue continue
} }
@ -103,7 +102,7 @@ func (a *announceProcessor) processQueue(queue chan string) {
// on lines matched // on lines matched
if err := a.onLinesMatched(a.indexer, tmpVars, rls); err != nil { if err := a.onLinesMatched(a.indexer, tmpVars, rls); err != nil {
a.log.Debug().Msgf("error match line: %v", "") a.log.Error().Err(err).Msg("error match line")
continue continue
} }
@ -136,6 +135,14 @@ func (a *announceProcessor) AddLineToQueue(channel string, line string) error {
return nil return nil
} }
func (a *announceProcessor) parseLine(pattern string, vars []string, tmpVars map[string]string, line string) (bool, error) {
if len(vars) > 0 {
return a.parseExtract(pattern, vars, tmpVars, line)
}
return a.parseMatchRegexp(pattern, tmpVars, line)
}
func (a *announceProcessor) parseExtract(pattern string, vars []string, tmpVars map[string]string, line string) (bool, error) { func (a *announceProcessor) parseExtract(pattern string, vars []string, tmpVars map[string]string, line string) (bool, error) {
rxp, err := regExMatch(pattern, line) rxp, err := regExMatch(pattern, line)
@ -161,11 +168,28 @@ func (a *announceProcessor) parseExtract(pattern string, vars []string, tmpVars
return true, nil return true, nil
} }
func (a *announceProcessor) parseMatchRegexp(pattern string, tmpVars map[string]string, line string) (bool, error) {
var re = regexp.MustCompile(`(?mi)` + pattern)
groupNames := re.SubexpNames()
for _, match := range re.FindAllStringSubmatch(line, -1) {
for groupIdx, group := range match {
name := groupNames[groupIdx]
if name == "" {
name = "raw"
}
tmpVars[name] = group
}
}
return true, nil
}
// onLinesMatched process vars into release // onLinesMatched process vars into release
func (a *announceProcessor) onLinesMatched(def *domain.IndexerDefinition, vars map[string]string, rls *domain.Release) error { func (a *announceProcessor) onLinesMatched(def *domain.IndexerDefinition, vars map[string]string, rls *domain.Release) error {
// map variables from regex capture onto release struct
if err := rls.MapVars(def, vars); err != nil { if err := rls.MapVars(def, vars); err != nil {
a.log.Error().Stack().Err(err).Msg("announce: could not map vars for release") a.log.Error().Err(err).Msg("announce: could not map vars for release")
return err return err
} }
@ -173,12 +197,38 @@ func (a *announceProcessor) onLinesMatched(def *domain.IndexerDefinition, vars m
// run before ParseMatch to not potentially use a reconstructed TorrentName // run before ParseMatch to not potentially use a reconstructed TorrentName
rls.ParseString(rls.TorrentName) rls.ParseString(rls.TorrentName)
// set baseUrl to default domain
baseUrl := def.URLS[0]
// override baseUrl
if def.BaseURL != "" {
baseUrl = def.BaseURL
}
// merge vars from regex captures on announce and vars from settings
mergedVars := mergeVars(vars, def.SettingsMap)
// parse torrentUrl // parse torrentUrl
if err := def.Parse.ParseMatch(vars, def.SettingsMap, rls); err != nil { matched, err := def.IRC.Parse.ParseMatch(baseUrl, mergedVars)
a.log.Error().Stack().Err(err).Msgf("announce: %v", err) if err != nil {
a.log.Error().Err(err).Msgf("announce: %v", err)
return err return err
} }
if matched != nil {
rls.TorrentURL = matched.TorrentURL
// only used by few indexers
if matched.TorrentName != "" {
rls.TorrentName = matched.TorrentName
}
}
// handle optional cookies
if v, ok := def.SettingsMap["cookie"]; ok {
rls.RawCookie = v
}
return nil return nil
} }
@ -191,14 +241,11 @@ func (a *announceProcessor) processTorrentUrl(match string, vars map[string]stri
} }
// merge extra vars with vars // merge extra vars with vars
if extraVars != nil {
for k, v := range extraVars { for k, v := range extraVars {
tmpVars[k] = v tmpVars[k] = v
} }
}
// handle url encode of values // handle url encode of values
if encode != nil {
for _, e := range encode { for _, e := range encode {
if v, ok := tmpVars[e]; ok { if v, ok := tmpVars[e]; ok {
// url encode value // url encode value
@ -206,7 +253,6 @@ func (a *announceProcessor) processTorrentUrl(match string, vars map[string]stri
tmpVars[e] = t tmpVars[e] = t
} }
} }
}
// setup text template to inject variables into // setup text template to inject variables into
tmpl, err := template.New("torrenturl").Parse(match) tmpl, err := template.New("torrenturl").Parse(match)
@ -226,6 +272,19 @@ func (a *announceProcessor) processTorrentUrl(match string, vars map[string]stri
return b.String(), nil return b.String(), nil
} }
// mergeVars merge maps
func mergeVars(data ...map[string]string) map[string]string {
tmpVars := map[string]string{}
for _, vars := range data {
// copy vars to new tmp map
for k, v := range vars {
tmpVars[k] = v
}
}
return tmpVars
}
func removeElement(s []string, i int) ([]string, error) { func removeElement(s []string, i int) ([]string, error) {
// s is [1,2,3,4,5,6], i is 2 // s is [1,2,3,4,5,6], i is 2
@ -246,7 +305,6 @@ func regExMatch(pattern string, value string) ([]string, error) {
rxp, err := regexp.Compile(pattern) rxp, err := regexp.Compile(pattern)
if err != nil { if err != nil {
return nil, err return nil, err
//return errors.Wrapf(err, "invalid regex: %s", value)
} }
matches := rxp.FindStringSubmatch(value) matches := rxp.FindStringSubmatch(value)

View file

@ -32,15 +32,14 @@ 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", "settings"). Insert("indexer").Columns("enabled", "name", "identifier", "implementation", "base_url", "settings").
Values(indexer.Enabled, indexer.Name, indexer.Identifier, indexer.Implementation, settings). Values(indexer.Enabled, indexer.Name, indexer.Identifier, 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 var retID int64
err = queryBuilder.QueryRowContext(ctx).Scan(&retID) if err = queryBuilder.QueryRowContext(ctx).Scan(&retID); err != nil {
if err != nil {
return nil, errors.Wrap(err, "error executing query") return nil, errors.Wrap(err, "error executing query")
} }
@ -59,6 +58,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("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)).
Where("id = ?", indexer.ID) Where("id = ?", indexer.ID)
@ -68,8 +68,7 @@ func (r *IndexerRepo) Update(ctx context.Context, indexer domain.Indexer) (*doma
return nil, errors.Wrap(err, "error building query") return nil, errors.Wrap(err, "error building query")
} }
_, err = r.db.handler.ExecContext(ctx, query, args...) if _, err = r.db.handler.ExecContext(ctx, query, args...); err != nil {
if err != nil {
return nil, errors.Wrap(err, "error executing query") return nil, errors.Wrap(err, "error executing query")
} }
@ -77,7 +76,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) {
rows, err := r.db.handler.QueryContext(ctx, "SELECT id, enabled, name, identifier, implementation, settings FROM indexer ORDER BY name ASC") rows, err := r.db.handler.QueryContext(ctx, "SELECT id, enabled, name, identifier, implementation, base_url, settings FROM indexer ORDER BY name ASC")
if err != nil { if err != nil {
return nil, errors.Wrap(err, "error executing query") return nil, errors.Wrap(err, "error executing query")
} }
@ -88,18 +87,18 @@ 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 sql.NullString var implementation, baseURL sql.NullString
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, &settings); err != nil { if err := rows.Scan(&f.ID, &f.Enabled, &f.Name, &f.Identifier, &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.Implementation = implementation.String
f.BaseURL = baseURL.String
err = json.Unmarshal([]byte(settings), &settingsMap) if err = json.Unmarshal([]byte(settings), &settingsMap); err != nil {
if err != nil {
return nil, errors.Wrap(err, "error unmarshal settings") return nil, errors.Wrap(err, "error unmarshal settings")
} }
@ -116,7 +115,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", "settings"). Select("id", "enabled", "name", "identifier", "implementation", "base_url", "settings").
From("indexer"). From("indexer").
Where("id = ?", id) Where("id = ?", id)
@ -132,13 +131,14 @@ func (r *IndexerRepo) FindByID(ctx context.Context, id int) (*domain.Indexer, er
var i domain.Indexer var i domain.Indexer
var implementation, settings sql.NullString var implementation, baseURL, settings sql.NullString
if err := row.Scan(&i.ID, &i.Enabled, &i.Name, &i.Identifier, &implementation, &settings); err != nil { if err := row.Scan(&i.ID, &i.Enabled, &i.Name, &i.Identifier, &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.Implementation = implementation.String
i.BaseURL = baseURL.String
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.String), &settingsMap); err != nil {
@ -153,7 +153,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", "settings"). Select("id", "enabled", "name", "identifier", "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("filter_indexer.filter_id = ?", id) Where("filter_indexer.filter_id = ?", id)
@ -176,16 +176,17 @@ 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
if err := rows.Scan(&f.ID, &f.Enabled, &f.Name, &f.Identifier, &settings); err != nil { if err := rows.Scan(&f.ID, &f.Enabled, &f.Name, &f.Identifier, &baseURL, &settings); err != nil {
return nil, errors.Wrap(err, "error scanning row") return nil, errors.Wrap(err, "error scanning row")
} }
err = json.Unmarshal([]byte(settings), &settingsMap) if err = json.Unmarshal([]byte(settings), &settingsMap); err != nil {
if err != nil {
return nil, errors.Wrap(err, "error unmarshal settings") return nil, errors.Wrap(err, "error unmarshal settings")
} }
f.BaseURL = baseURL.String
f.Settings = settingsMap f.Settings = settingsMap
indexers = append(indexers, f) indexers = append(indexers, f)

View file

@ -16,6 +16,7 @@ CREATE TABLE indexer
id SERIAL PRIMARY KEY, id SERIAL PRIMARY KEY,
identifier TEXT, identifier TEXT,
implementation TEXT, implementation TEXT,
base_url TEXT,
enabled BOOLEAN, enabled BOOLEAN,
name TEXT NOT NULL, name TEXT NOT NULL,
settings TEXT, settings TEXT,
@ -615,4 +616,7 @@ CREATE INDEX indexer_identifier_index
UPDATE irc_network UPDATE irc_network
SET auth_mechanism = 'SASL_PLAIN';`, SET auth_mechanism = 'SASL_PLAIN';`,
`ALTER TABLE indexer
ADD COLUMN base_url TEXT;
`,
} }

View file

@ -16,6 +16,7 @@ CREATE TABLE indexer
id INTEGER PRIMARY KEY, id INTEGER PRIMARY KEY,
identifier TEXT, identifier TEXT,
implementation TEXT, implementation TEXT,
base_url TEXT,
enabled BOOLEAN, enabled BOOLEAN,
name TEXT NOT NULL, name TEXT NOT NULL,
settings TEXT, settings TEXT,
@ -959,4 +960,7 @@ DROP TABLE irc_network;
ALTER TABLE irc_network_dg_tmp ALTER TABLE irc_network_dg_tmp
RENAME TO irc_network; RENAME TO irc_network;
`, `,
`ALTER TABLE indexer
ADD COLUMN base_url TEXT;
`,
} }

View file

@ -3,10 +3,11 @@ package domain
import ( import (
"bytes" "bytes"
"context" "context"
"errors"
"net/url" "net/url"
"text/template" "text/template"
"github.com/autobrr/autobrr/pkg/errors"
"github.com/Masterminds/sprig/v3" "github.com/Masterminds/sprig/v3"
"github.com/dustin/go-humanize" "github.com/dustin/go-humanize"
) )
@ -26,6 +27,7 @@ type Indexer struct {
Identifier string `json:"identifier"` Identifier string `json:"identifier"`
Enabled bool `json:"enabled"` Enabled bool `json:"enabled"`
Implementation string `json:"implementation"` Implementation string `json:"implementation"`
BaseURL string `json:"base_url,omitempty"`
Settings map[string]string `json:"settings,omitempty"` Settings map[string]string `json:"settings,omitempty"`
} }
@ -34,6 +36,7 @@ type IndexerDefinition struct {
Name string `json:"name"` Name string `json:"name"`
Identifier string `json:"identifier"` Identifier string `json:"identifier"`
Implementation string `json:"implementation"` Implementation string `json:"implementation"`
BaseURL string `json:"base_url,omitempty"`
Enabled bool `json:"enabled,omitempty"` Enabled bool `json:"enabled,omitempty"`
Description string `json:"description"` Description string `json:"description"`
Language string `json:"language"` Language string `json:"language"`
@ -46,7 +49,6 @@ type IndexerDefinition struct {
IRC *IndexerIRC `json:"irc,omitempty"` IRC *IndexerIRC `json:"irc,omitempty"`
Torznab *Torznab `json:"torznab,omitempty"` Torznab *Torznab `json:"torznab,omitempty"`
RSS *FeedSettings `json:"rss,omitempty"` RSS *FeedSettings `json:"rss,omitempty"`
Parse *IndexerParse `json:"parse,omitempty"`
} }
func (i IndexerDefinition) HasApi() bool { func (i IndexerDefinition) HasApi() bool {
@ -58,6 +60,55 @@ func (i IndexerDefinition) HasApi() bool {
return false return false
} }
type IndexerDefinitionCustom struct {
ID int `json:"id,omitempty"`
Name string `json:"name"`
Identifier string `json:"identifier"`
Implementation string `json:"implementation"`
BaseURL string `json:"base_url,omitempty"`
Enabled bool `json:"enabled,omitempty"`
Description string `json:"description"`
Language string `json:"language"`
Privacy string `json:"privacy"`
Protocol string `json:"protocol"`
URLS []string `json:"urls"`
Supports []string `json:"supports"`
Settings []IndexerSetting `json:"settings,omitempty"`
SettingsMap map[string]string `json:"-"`
IRC *IndexerIRC `json:"irc,omitempty"`
Torznab *Torznab `json:"torznab,omitempty"`
RSS *FeedSettings `json:"rss,omitempty"`
Parse *IndexerIRCParse `json:"parse,omitempty"`
}
func (i *IndexerDefinitionCustom) ToIndexerDefinition() *IndexerDefinition {
d := &IndexerDefinition{
ID: i.ID,
Name: i.Name,
Identifier: i.Identifier,
Implementation: i.Implementation,
BaseURL: i.BaseURL,
Enabled: i.Enabled,
Description: i.Description,
Language: i.Language,
Privacy: i.Privacy,
Protocol: i.Protocol,
URLS: i.URLS,
Supports: i.Supports,
Settings: i.Settings,
SettingsMap: i.SettingsMap,
IRC: i.IRC,
Torznab: i.Torznab,
RSS: i.RSS,
}
if i.IRC != nil && i.Parse != nil {
i.IRC.Parse = i.Parse
}
return d
}
type IndexerSetting struct { type IndexerSetting struct {
Name string `json:"name"` Name string `json:"name"`
Required bool `json:"required,omitempty"` Required bool `json:"required,omitempty"`
@ -89,6 +140,7 @@ type IndexerIRC struct {
Announcers []string `json:"announcers"` Announcers []string `json:"announcers"`
SettingsMap map[string]string `json:"-"` SettingsMap map[string]string `json:"-"`
Settings []IndexerSetting `json:"settings"` Settings []IndexerSetting `json:"settings"`
Parse *IndexerIRCParse `json:"parse,omitempty"`
} }
func (i IndexerIRC) ValidAnnouncer(announcer string) bool { func (i IndexerIRC) ValidAnnouncer(announcer string) bool {
@ -109,48 +161,39 @@ func (i IndexerIRC) ValidChannel(channel string) bool {
return false return false
} }
type IndexerParse struct { type IndexerIRCParse struct {
Type string `json:"type"` Type string `json:"type"`
ForceSizeUnit string `json:"forcesizeunit"` ForceSizeUnit string `json:"forcesizeunit"`
Lines []IndexerParseExtract `json:"lines"` Lines []IndexerIRCParseLine `json:"lines"`
Match IndexerParseMatch `json:"match"` Match IndexerIRCParseMatch `json:"match"`
} }
type IndexerParseExtract struct { type IndexerIRCParseLine struct {
Test []string `json:"test"` Test []string `json:"test"`
Pattern string `json:"pattern"` Pattern string `json:"pattern"`
Vars []string `json:"vars"` Vars []string `json:"vars"`
} }
type IndexerParseMatch struct { type IndexerIRCParseMatch struct {
TorrentURL string `json:"torrenturl"` TorrentURL string `json:"torrenturl"`
TorrentName string `json:"torrentname"` TorrentName string `json:"torrentname"`
Encode []string `json:"encode"` Encode []string `json:"encode"`
} }
func (p *IndexerParse) ParseMatch(vars map[string]string, extraVars map[string]string, release *Release) error { type IndexerIRCParseMatched struct {
tmpVars := map[string]string{} TorrentURL string
TorrentName string
}
// copy vars to new tmp map func (p *IndexerIRCParse) ParseMatch(baseURL string, vars map[string]string) (*IndexerIRCParseMatched, error) {
for k, v := range vars { matched := &IndexerIRCParseMatched{}
tmpVars[k] = v
}
// merge extra vars with vars
if extraVars != nil {
for k, v := range extraVars {
tmpVars[k] = v
}
}
// handle url encode of values // handle url encode of values
if p.Match.Encode != nil {
for _, e := range p.Match.Encode { for _, e := range p.Match.Encode {
if v, ok := tmpVars[e]; ok { if v, ok := vars[e]; ok {
// url encode value // url encode value
t := url.QueryEscape(v) t := url.QueryEscape(v)
tmpVars[e] = t vars[e] = t
}
} }
} }
@ -158,38 +201,52 @@ func (p *IndexerParse) ParseMatch(vars map[string]string, extraVars map[string]s
// setup text template to inject variables into // setup text template to inject variables into
tmpl, err := template.New("torrenturl").Funcs(sprig.TxtFuncMap()).Parse(p.Match.TorrentURL) tmpl, err := template.New("torrenturl").Funcs(sprig.TxtFuncMap()).Parse(p.Match.TorrentURL)
if err != nil { if err != nil {
return errors.New("could not create torrent url template") return nil, errors.New("could not create torrent url template")
} }
var urlBytes bytes.Buffer var urlBytes bytes.Buffer
if err := tmpl.Execute(&urlBytes, &tmpVars); err != nil { if err := tmpl.Execute(&urlBytes, &vars); err != nil {
return errors.New("could not write torrent url template output") return nil, errors.New("could not write torrent url template output")
} }
release.TorrentURL = urlBytes.String() parsedUrl, err := url.Parse(urlBytes.String())
if err != nil {
return nil, err
}
// for backwards compatibility remove Host and Scheme to rebuild url
if parsedUrl.Host != "" {
parsedUrl.Host = ""
}
if parsedUrl.Scheme != "" {
parsedUrl.Scheme = ""
}
// join baseURL with query
torrentURL, err := url.JoinPath(baseURL, parsedUrl.Path)
if err != nil {
return nil, errors.Wrap(err, "could not join torrent url")
}
matched.TorrentURL = torrentURL
} }
if p.Match.TorrentName != "" { if p.Match.TorrentName != "" {
// setup text template to inject variables into // setup text template to inject variables into
tmplName, err := template.New("torrentname").Funcs(sprig.TxtFuncMap()).Parse(p.Match.TorrentName) tmplName, err := template.New("torrentname").Funcs(sprig.TxtFuncMap()).Parse(p.Match.TorrentName)
if err != nil { if err != nil {
return err return nil, err
} }
var nameBytes bytes.Buffer var nameBytes bytes.Buffer
if err := tmplName.Execute(&nameBytes, &tmpVars); err != nil { if err := tmplName.Execute(&nameBytes, &vars); err != nil {
return errors.New("could not write torrent name template output") return nil, errors.New("could not write torrent name template output")
} }
release.TorrentName = nameBytes.String() matched.TorrentName = nameBytes.String()
} }
// handle cookies return matched, nil
if v, ok := extraVars["cookie"]; ok {
release.RawCookie = v
}
return nil
} }
type TorrentBasic struct { type TorrentBasic struct {

View file

@ -6,23 +6,22 @@ import (
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
) )
func TestIndexerParse_ParseMatch(t *testing.T) { func TestIndexerIRCParse_ParseMatch(t *testing.T) {
type fields struct { type fields struct {
Type string Type string
ForceSizeUnit string ForceSizeUnit string
Lines []IndexerParseExtract Lines []IndexerIRCParseLine
Match IndexerParseMatch Match IndexerIRCParseMatch
} }
type args struct { type args struct {
baseURL string
vars map[string]string vars map[string]string
extraVars map[string]string
release *Release
} }
tests := []struct { tests := []struct {
name string name string
fields fields fields fields
args args args args
expect *Release want *IndexerIRCParseMatched
wantErr bool wantErr bool
}{ }{
{ {
@ -30,7 +29,7 @@ func TestIndexerParse_ParseMatch(t *testing.T) {
fields: fields{ fields: fields{
Type: "", Type: "",
ForceSizeUnit: "", ForceSizeUnit: "",
Lines: []IndexerParseExtract{ Lines: []IndexerIRCParseLine{
{ {
Test: nil, Test: nil,
Pattern: "New Torrent Announcement:\\s*<([^>]*)>\\s*Name:'(.*)' uploaded by '([^']*)'\\s*(freeleech)*\\s*-\\s*(https?\\:\\/\\/[^\\/]+\\/)torrent\\/(\\d+)", Pattern: "New Torrent Announcement:\\s*<([^>]*)>\\s*Name:'(.*)' uploaded by '([^']*)'\\s*(freeleech)*\\s*-\\s*(https?\\:\\/\\/[^\\/]+\\/)torrent\\/(\\d+)",
@ -44,39 +43,25 @@ func TestIndexerParse_ParseMatch(t *testing.T) {
}, },
}, },
}, },
Match: IndexerParseMatch{ Match: IndexerIRCParseMatch{
TorrentURL: "{{ .baseUrl }}rss/download/{{ .torrentId }}/{{ .rsskey }}/{{ .torrentName }}.torrent", TorrentURL: "rss/download/{{ .torrentId }}/{{ .rsskey }}/{{ .torrentName }}.torrent",
TorrentName: "",
Encode: []string{"torrentName"}, Encode: []string{"torrentName"},
}, },
}, },
args: args{ args: args{
baseURL: "https://mock.local/",
vars: map[string]string{ vars: map[string]string{
"category": "TV :: Episodes HD", "category": "TV :: Episodes HD",
"torrentName": "The Show 2019 S03E08 2160p DV WEBRip 6CH x265 HEVC-GROUP", "torrentName": "The Show 2019 S03E08 2160p DV WEBRip 6CH x265 HEVC-GROUP",
"uploader": "Anonymous", "uploader": "Anonymous",
"freeleech": "", "freeleech": "",
"baseUrl": "https://mock.org/", "baseUrl": "https://mock.local/",
"torrentId": "240860011", "torrentId": "240860011",
},
extraVars: map[string]string{
"rsskey": "00000000000000000000", "rsskey": "00000000000000000000",
}, },
release: &Release{
Indexer: "mock",
FilterStatus: ReleaseStatusFilterPending,
Rejections: []string{},
Protocol: ReleaseProtocolTorrent,
Implementation: ReleaseImplementationIRC,
}, },
}, want: &IndexerIRCParseMatched{
expect: &Release{ TorrentURL: "https://mock.local/rss/download/240860011/00000000000000000000/The+Show+2019+S03E08+2160p+DV+WEBRip+6CH+x265+HEVC-GROUP.torrent",
Indexer: "mock",
FilterStatus: ReleaseStatusFilterPending,
Rejections: []string{},
Protocol: ReleaseProtocolTorrent,
Implementation: ReleaseImplementationIRC,
TorrentURL: "https://mock.org/rss/download/240860011/00000000000000000000/The+Show+2019+S03E08+2160p+DV+WEBRip+6CH+x265+HEVC-GROUP.torrent",
}, },
wantErr: false, wantErr: false,
}, },
@ -85,7 +70,7 @@ func TestIndexerParse_ParseMatch(t *testing.T) {
fields: fields{ fields: fields{
Type: "", Type: "",
ForceSizeUnit: "", ForceSizeUnit: "",
Lines: []IndexerParseExtract{ Lines: []IndexerIRCParseLine{
{ {
Test: nil, Test: nil,
Pattern: `(.*?)(?: - )?(Visual Novel|Light Novel|TV.*|Movie|Manga|OVA|ONA|DVD Special|BD Special|Oneshot|Anthology|Manhwa|Manhua|Artbook|Game|Live Action.*|)[\s\p{Zs}]{2,}\[(\d+)\] :: (.*?)(?: \/ (?:RAW|Softsubs|Hardsubs|Translated)\s\((.+)\)(?:.*Episode\s(\d+))?(?:.*(Freeleech))?.*)? \|\| (https.*)\/torrents.*\?id=\d+&torrentid=(\d+) \|\| (.+?(?:(?:\|\| Uploaded by|$))?) (?:\|\| Uploaded by: (.*))?$`, Pattern: `(.*?)(?: - )?(Visual Novel|Light Novel|TV.*|Movie|Manga|OVA|ONA|DVD Special|BD Special|Oneshot|Anthology|Manhwa|Manhua|Artbook|Game|Live Action.*|)[\s\p{Zs}]{2,}\[(\d+)\] :: (.*?)(?: \/ (?:RAW|Softsubs|Hardsubs|Translated)\s\((.+)\)(?:.*Episode\s(\d+))?(?:.*(Freeleech))?.*)? \|\| (https.*)\/torrents.*\?id=\d+&torrentid=(\d+) \|\| (.+?(?:(?:\|\| Uploaded by|$))?) (?:\|\| Uploaded by: (.*))?$`,
@ -104,13 +89,14 @@ func TestIndexerParse_ParseMatch(t *testing.T) {
}, },
}, },
}, },
Match: IndexerParseMatch{ Match: IndexerIRCParseMatch{
TorrentURL: "{{ .baseUrl }}/torrent/{{ .torrentId }}/download/{{ .passkey }}", TorrentURL: "/torrent/{{ .torrentId }}/download/{{ .passkey }}",
TorrentName: `{{ if .releaseGroup }}[{{ .releaseGroup }}] {{ end }}{{ .torrentName }} [{{ .year }}] {{ if .releaseEpisode }}{{ printf "- %02s " .releaseEpisode }}{{ end }}{{ print "[" .releaseTags "]" | replace " / " "][" }}`, TorrentName: `{{ if .releaseGroup }}[{{ .releaseGroup }}] {{ end }}{{ .torrentName }} [{{ .year }}] {{ if .releaseEpisode }}{{ printf "- %02s " .releaseEpisode }}{{ end }}{{ print "[" .releaseTags "]" | replace " / " "][" }}`,
Encode: nil, Encode: nil,
}, },
}, },
args: args{ args: args{
baseURL: "https://mock.local/",
vars: map[string]string{ vars: map[string]string{
"torrentName": "Great BluRay SoftSubbed Anime", "torrentName": "Great BluRay SoftSubbed Anime",
"category": "TV Series", "category": "TV Series",
@ -119,45 +105,113 @@ func TestIndexerParse_ParseMatch(t *testing.T) {
"releaseGroup": "Softsubs", "releaseGroup": "Softsubs",
"releaseEpisode": "", "releaseEpisode": "",
"freeleech": "freeleech", "freeleech": "freeleech",
"baseUrl": "https://mock.org", "baseUrl": "https://mock.local",
"torrentId": "240860011", "torrentId": "240860011",
"tags": "comedy, drama, school.life, sports", "tags": "comedy, drama, school.life, sports",
"uploader": "Uploader", "uploader": "Uploader",
},
extraVars: map[string]string{
"passkey": "00000000000000000000", "passkey": "00000000000000000000",
}, },
release: &Release{
Indexer: "mock",
FilterStatus: ReleaseStatusFilterPending,
Rejections: []string{},
Protocol: ReleaseProtocolTorrent,
Implementation: ReleaseImplementationIRC,
}, },
}, want: &IndexerIRCParseMatched{
expect: &Release{ TorrentURL: "https://mock.local/torrent/240860011/download/00000000000000000000",
Indexer: "mock",
FilterStatus: ReleaseStatusFilterPending,
Rejections: []string{},
Protocol: ReleaseProtocolTorrent,
Implementation: ReleaseImplementationIRC,
TorrentURL: "https://mock.org/torrent/240860011/download/00000000000000000000",
TorrentName: "[Softsubs] Great BluRay SoftSubbed Anime [2020] [Blu-ray][MKV][h264 10-bit][1080p][FLAC 2.0][Dual Audio][Softsubs (Sub Group)][Freeleech]", TorrentName: "[Softsubs] Great BluRay SoftSubbed Anime [2020] [Blu-ray][MKV][h264 10-bit][1080p][FLAC 2.0][Dual Audio][Softsubs (Sub Group)][Freeleech]",
}, },
wantErr: false, wantErr: false,
}, },
{
name: "test_03",
fields: fields{
Type: "",
ForceSizeUnit: "",
Lines: []IndexerIRCParseLine{
{
Test: nil,
Pattern: "New Torrent Announcement:\\s*<([^>]*)>\\s*Name:'(.*)' uploaded by '([^']*)'\\s*(freeleech)*\\s*-\\s*(https?\\:\\/\\/[^\\/]+\\/)torrent\\/(\\d+)",
Vars: []string{
"category",
"torrentName",
"uploader",
"freeleech",
"baseUrl",
"torrentId",
},
},
},
Match: IndexerIRCParseMatch{
TorrentURL: "{{ .baseUrl }}rss/download/{{ .torrentId }}/{{ .rsskey }}/{{ .torrentName }}.torrent",
Encode: []string{"torrentName"},
},
},
args: args{
baseURL: "https://mock.local/",
vars: map[string]string{
"category": "TV :: Episodes HD",
"torrentName": "The Show 2019 S03E08 2160p DV WEBRip 6CH x265 HEVC-GROUP",
"uploader": "Anonymous",
"freeleech": "",
"baseUrl": "https://mock.local/",
"torrentId": "240860011",
"rsskey": "00000000000000000000",
},
},
want: &IndexerIRCParseMatched{
TorrentURL: "https://mock.local/rss/download/240860011/00000000000000000000/The+Show+2019+S03E08+2160p+DV+WEBRip+6CH+x265+HEVC-GROUP.torrent",
},
wantErr: false,
},
{
name: "test_04",
fields: fields{
Type: "",
ForceSizeUnit: "",
Lines: []IndexerIRCParseLine{
{
Test: nil,
Pattern: "New Torrent Announcement:\\s*<([^>]*)>\\s*Name:'(.*)' uploaded by '([^']*)'\\s*(freeleech)*\\s*-\\s*(https?\\:\\/\\/[^\\/]+\\/)torrent\\/(\\d+)",
Vars: []string{
"category",
"torrentName",
"uploader",
"freeleech",
"baseUrl",
"torrentId",
},
},
},
Match: IndexerIRCParseMatch{
TorrentURL: "https://mock.local/rss/download/{{ .torrentId }}/{{ .rsskey }}/{{ .torrentName }}.torrent",
Encode: []string{"torrentName"},
},
},
args: args{
baseURL: "https://mock.local/",
vars: map[string]string{
"category": "TV :: Episodes HD",
"torrentName": "The Show 2019 S03E08 2160p DV WEBRip 6CH x265 HEVC-GROUP",
"uploader": "Anonymous",
"freeleech": "",
"baseUrl": "https://mock.local/",
"torrentId": "240860011",
"rsskey": "00000000000000000000",
},
},
want: &IndexerIRCParseMatched{
TorrentURL: "https://mock.local/rss/download/240860011/00000000000000000000/The+Show+2019+S03E08+2160p+DV+WEBRip+6CH+x265+HEVC-GROUP.torrent",
},
wantErr: false,
},
} }
for _, tt := range tests { for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) { t.Run(tt.name, func(t *testing.T) {
p := &IndexerParse{ p := &IndexerIRCParse{
Type: tt.fields.Type, Type: tt.fields.Type,
ForceSizeUnit: tt.fields.ForceSizeUnit, ForceSizeUnit: tt.fields.ForceSizeUnit,
Lines: tt.fields.Lines, Lines: tt.fields.Lines,
Match: tt.fields.Match, Match: tt.fields.Match,
} }
p.ParseMatch(tt.args.vars, tt.args.extraVars, tt.args.release) got, _ := p.ParseMatch(tt.args.baseURL, tt.args.vars)
assert.Equal(t, tt.expect, tt.args.release) assert.Equal(t, tt.want, got)
}) })
} }
} }

View file

@ -219,8 +219,6 @@ func (r *Release) ParseString(title string) {
} }
r.ParseReleaseTagsString(r.ReleaseTags) r.ParseReleaseTagsString(r.ReleaseTags)
return
} }
var ErrUnrecoverableError = errors.New("unrecoverable error") var ErrUnrecoverableError = errors.New("unrecoverable error")
@ -264,8 +262,6 @@ func (r *Release) ParseReleaseTagsString(tags string) {
if r.AudioChannels == "" && t.Channels != "" { if r.AudioChannels == "" && t.Channels != "" {
r.AudioChannels = t.Channels r.AudioChannels = t.Channels
} }
return
} }
func (r *Release) ParseSizeBytesString(size string) { func (r *Release) ParseSizeBytesString(size string) {
@ -401,7 +397,7 @@ func (r *Release) RejectionsString() string {
return "" return ""
} }
// MapVars better name // MapVars map vars from regex captures to fields on release
func (r *Release) MapVars(def *IndexerDefinition, varMap map[string]string) error { func (r *Release) MapVars(def *IndexerDefinition, varMap map[string]string) error {
if torrentName, err := getStringMapValue(varMap, "torrentName"); err != nil { if torrentName, err := getStringMapValue(varMap, "torrentName"); err != nil {
@ -444,16 +440,12 @@ func (r *Release) MapVars(def *IndexerDefinition, varMap map[string]string) erro
switch freeleechPercentInt { switch freeleechPercentInt {
case 25: case 25:
r.Bonus = append(r.Bonus, "Freeleech25") r.Bonus = append(r.Bonus, "Freeleech25")
break
case 50: case 50:
r.Bonus = append(r.Bonus, "Freeleech50") r.Bonus = append(r.Bonus, "Freeleech50")
break
case 75: case 75:
r.Bonus = append(r.Bonus, "Freeleech75") r.Bonus = append(r.Bonus, "Freeleech75")
break
case 100: case 100:
r.Bonus = append(r.Bonus, "Freeleech100") r.Bonus = append(r.Bonus, "Freeleech100")
break
} }
} }
@ -464,8 +456,8 @@ func (r *Release) MapVars(def *IndexerDefinition, varMap map[string]string) erro
if torrentSize, err := getStringMapValue(varMap, "torrentSize"); err == nil { if torrentSize, err := getStringMapValue(varMap, "torrentSize"); err == nil {
// handling for indexer who doesn't explicitly set which size unit is used like (AR) // handling for indexer who doesn't explicitly set which size unit is used like (AR)
if def.Parse != nil && def.Parse.ForceSizeUnit != "" { if def.IRC != nil && def.IRC.Parse != nil && def.IRC.Parse.ForceSizeUnit != "" {
torrentSize = fmt.Sprintf("%v %v", torrentSize, def.Parse.ForceSizeUnit) torrentSize = fmt.Sprintf("%v %v", torrentSize, def.IRC.Parse.ForceSizeUnit)
} }
size, err := humanize.ParseBytes(torrentSize) size, err := humanize.ParseBytes(torrentSize)

View file

@ -449,7 +449,7 @@ func TestRelease_MapVars(t *testing.T) {
"torrentSize": "10000", "torrentSize": "10000",
"tags": "hip.hop,rhythm.and.blues, 2000s", "tags": "hip.hop,rhythm.and.blues, 2000s",
}, },
definition: IndexerDefinition{Parse: &IndexerParse{ForceSizeUnit: "MB"}}, definition: IndexerDefinition{IRC: &IndexerIRC{Parse: &IndexerIRCParse{ForceSizeUnit: "MB"}}},
}, },
}, },
{ {
@ -769,10 +769,7 @@ func TestRelease_DownloadTorrentFile(t *testing.T) {
TorrentURL: fmt.Sprintf("%v/%v", ts.URL, 401), TorrentURL: fmt.Sprintf("%v/%v", ts.URL, 401),
}, },
wantErr: func(t assert.TestingT, err error, i ...interface{}) bool { wantErr: func(t assert.TestingT, err error, i ...interface{}) bool {
if err != nil { return err != nil
return true
}
return false
}, },
}, },
{ {
@ -783,10 +780,7 @@ func TestRelease_DownloadTorrentFile(t *testing.T) {
TorrentURL: fmt.Sprintf("%v/%v", ts.URL, 403), TorrentURL: fmt.Sprintf("%v/%v", ts.URL, 403),
}, },
wantErr: func(t assert.TestingT, err error, i ...interface{}) bool { wantErr: func(t assert.TestingT, err error, i ...interface{}) bool {
if err != nil { return err != nil
return true
}
return false
}, },
}, },
{ {
@ -797,13 +791,11 @@ func TestRelease_DownloadTorrentFile(t *testing.T) {
TorrentURL: fmt.Sprintf("%v/%v", ts.URL, "file.torrent"), TorrentURL: fmt.Sprintf("%v/%v", ts.URL, "file.torrent"),
}, },
wantErr: func(t assert.TestingT, err error, i ...interface{}) bool { wantErr: func(t assert.TestingT, err error, i ...interface{}) bool {
if err != nil { return err != nil
return true
}
return false
}, },
}, },
} }
for _, tt := range tests { for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) { t.Run(tt.name, func(t *testing.T) {
r := &Release{ r := &Release{
@ -861,7 +853,7 @@ func TestRelease_DownloadTorrentFile(t *testing.T) {
Filter: tt.fields.Filter, Filter: tt.fields.Filter,
ActionStatus: tt.fields.ActionStatus, ActionStatus: tt.fields.ActionStatus,
} }
tt.wantErr(t, r.DownloadTorrentFile(), fmt.Sprintf("DownloadTorrentFile()")) tt.wantErr(t, r.DownloadTorrentFile(), "DownloadTorrentFile()")
}) })
} }
} }

View file

@ -5,7 +5,7 @@ identifier: acidlounge
description: Small general tracker. description: Small general tracker.
language: en-us language: en-us
urls: urls:
- https://www.acid-lounge.org.uk - https://www.acid-lounge.org.uk/
privacy: private privacy: private
protocol: torrent protocol: torrent
supports: supports:
@ -55,7 +55,7 @@ irc:
label: NickServ Password label: NickServ Password
help: NickServ password help: NickServ password
parse: parse:
type: single type: single
lines: lines:
- test: - test:
@ -64,7 +64,7 @@ parse:
- "(XXX/0-Day) Cute.Stuff.69.XXX.VR180.2700p.MP4-s0ez https://www.acid-lounge.org.uk/details.php?id=30444221135&hit=1" - "(XXX/0-Day) Cute.Stuff.69.XXX.VR180.2700p.MP4-s0ez https://www.acid-lounge.org.uk/details.php?id=30444221135&hit=1"
- "(Movies/HD) Have.You.Seen.The.Cat.Tonight-WhereThat https://www.acid-lounge.org.uk/details.php?id=3018979898&hit=1" - "(Movies/HD) Have.You.Seen.The.Cat.Tonight-WhereThat https://www.acid-lounge.org.uk/details.php?id=3018979898&hit=1"
- "(TV-HD/X264) The.Eggerton.S01E01.720p.WEB.h264-OTA https://www.acid-lounge.org.uk/details.php?id=302099&hit=1" - "(TV-HD/X264) The.Eggerton.S01E01.720p.WEB.h264-OTA https://www.acid-lounge.org.uk/details.php?id=302099&hit=1"
pattern: '\((.*)\) (.*) (https?\:\/\/[^\/]+).*id=(\d+)' pattern: '\((.*)\) (.*) (https?\:\/\/[^\/]+\/).*id=(\d+)'
vars: vars:
- category - category
- torrentName - torrentName
@ -72,4 +72,4 @@ parse:
- torrentId - torrentId
match: match:
torrenturl: "{{ .baseUrl }}/rssdownload.php?passkey={{ .passkey }}&uid={{ .uid }}&tid={{ .torrentId }}" torrenturl: "/rssdownload.php?passkey={{ .passkey }}&uid={{ .uid }}&tid={{ .torrentId }}"

View file

@ -60,13 +60,13 @@ irc:
label: Invite command label: Invite command
help: Invite auth with Voyager. Replace USERNAME with site nick and set IRCKEY. help: Invite auth with Voyager. Replace USERNAME with site nick and set IRCKEY.
parse: parse:
type: multi type: multi
forcesizeunit: MB forcesizeunit: MB
lines: lines:
- test: - test:
- "[New Release]-[MovieHD]-[That.Movie.2017.INTERNAL.1080p.BluRay.CRF.x264-GROUP]-[URL]-[ https://alpharatio.cc/torrents.php?id=000000 ]-[ 000000 ]-[ Uploaded 2 Mins, 59 Secs after pre. ]" - "[new release]-[moviehd]-[that.movie.2017.internal.1080p.bluray.crf.x264-group]-[url]-[ https://alpharatio.cc/torrents.php?id=000000 ]-[ 000000 ]-[ uploaded 2 mins, 59 secs after pre. ]"
pattern: \[New Release\]-\[(.*)\]-\[(.*)\]-\[URL\]-\[ (https?://.*)id=\d+ \]-\[ (\d+) \](?:-\[ Uploaded (.*) after pre. ])? pattern: \[new release\]-\[(.*)\]-\[(.*)\]-\[url\]-\[ (https?://.+/).+id=\d+ \]-\[ (\d+) \](?:-\[ uploaded (.*) after pre. ])?
vars: vars:
- category - category
- torrentName - torrentName
@ -83,4 +83,4 @@ parse:
- auto - auto
match: match:
torrenturl: "{{ .baseUrl }}action=download&id={{ .torrentId }}&authkey={{ .authkey }}&torrent_pass={{ .torrent_pass }}" torrenturl: "/torrents.php?action=download&id={{ .torrentId }}&authkey={{ .authkey }}&torrent_pass={{ .torrent_pass }}"

View file

@ -54,7 +54,7 @@ irc:
label: Invite command label: Invite command
help: Invite auth with Satsuki, animebytes.tv/irc. Replace USERNAME and IRCKEY. help: Invite auth with Satsuki, animebytes.tv/irc. Replace USERNAME and IRCKEY.
parse: parse:
type: single type: single
lines: lines:
- test: - test:
@ -67,7 +67,7 @@ parse:
- "Best Visual Novel - Visual Novel [2006] :: Game / PC / Unarchived / Hentai (Censored) || https://animebytes.tv/torrents.php?id=00000&torrentid=00000 || nukige || Uploaded by: Uploader" - "Best Visual Novel - Visual Novel [2006] :: Game / PC / Unarchived / Hentai (Censored) || https://animebytes.tv/torrents.php?id=00000&torrentid=00000 || nukige || Uploaded by: Uploader"
- "Artist Name - Album of awesome Music [1991] :: MP3 / V0 (VBR) / CD || https://animebytes.tv/torrents2.php?id=00000&torrentid=000000 || ambient, folk || Uploaded by: Uploader" - "Artist Name - Album of awesome Music [1991] :: MP3 / V0 (VBR) / CD || https://animebytes.tv/torrents2.php?id=00000&torrentid=000000 || ambient, folk || Uploaded by: Uploader"
- "Awesome Series - TV Series [2022] :: Web / MKV / h264 / 1080p / AAC 2.0 / Softsubs (Sub Group) / Episode 1 / Freeleech || https://animebytes.tv/torrents.php?id=00000&torrentid=000000 || || Uploaded by: Uploader" - "Awesome Series - TV Series [2022] :: Web / MKV / h264 / 1080p / AAC 2.0 / Softsubs (Sub Group) / Episode 1 / Freeleech || https://animebytes.tv/torrents.php?id=00000&torrentid=000000 || || Uploaded by: Uploader"
pattern: '(.*?)(?: - )?(Visual Novel|Light Novel|TV.*|Movie|Manga|OVA|ONA|DVD Special|BD Special|Oneshot|Anthology|Manhwa|Manhua|Artbook|Game|Live Action.*|)[\s\p{Zs}]{2,}\[(\d+)\] :: (.*?)(?: \/ (?:RAW|Softsubs|Hardsubs|Translated)\s\((.+)\)(?:.*Episode\s(\d+))?(?:.*(Freeleech))?.*)?(?:.?\|\|.?)?(https.*)\/torrents.*\?id=\d+&torrentid=(\d+)(?:.?\|\|.?)?([A-Za-z,. ]+\w)?(?:.?\|\|.?)?(?:Uploaded by: (.*))?' pattern: '(.*?)(?: - )?(Visual Novel|Light Novel|TV.*|Movie|Manga|OVA|ONA|DVD Special|BD Special|Oneshot|Anthology|Manhwa|Manhua|Artbook|Game|Live Action.*|)[\s\p{Zs}]{2,}\[(\d+)\] :: (.*?)(?: \/ (?:RAW|Softsubs|Hardsubs|Translated)\s\((.+)\)(?:.*Episode\s(\d+))?(?:.*(Freeleech))?.*)?(?:.?\|\|.?)?(https.+\/)torrents.*\?id=\d+&torrentid=(\d+)(?:.?\|\|.?)?([A-Za-z,. ]+\w)?(?:.?\|\|.?)?(?:Uploaded by: (.*))?'
vars: vars:
- torrentName - torrentName
- category - category
@ -82,5 +82,5 @@ parse:
- uploader - uploader
match: match:
torrenturl: "{{ .baseUrl }}/torrent/{{ .torrentId }}/download/{{ .passkey }}" torrenturl: "/torrent/{{ .torrentId }}/download/{{ .passkey }}"
torrentname: "{{ if .releaseGroup }}[{{ .releaseGroup }}] {{ end }}{{ .torrentName }} {{ if .releaseEpisode }}{{ printf \"- %02s \" .releaseEpisode }}{{ end }} {{ if .year }}[{{ .year }}]{{ end }}{{ print \"[\" .releaseTags \"]\" | replace \" / \" \"][\" }}" torrentname: "{{ if .releaseGroup }}[{{ .releaseGroup }}] {{ end }}{{ .torrentName }} {{ if .releaseEpisode }}{{ printf \"- %02s \" .releaseEpisode }}{{ end }} {{ if .year }}[{{ .year }}]{{ end }}{{ print \"[\" .releaseTags \"]\" | replace \" / \" \"][\" }}"

View file

@ -55,7 +55,7 @@ irc:
label: Invite command label: Invite command
help: Invite auth with Millie. Replace IRCKEY. help: Invite auth with Millie. Replace IRCKEY.
parse: parse:
type: single type: single
lines: lines:
- test: - test:
@ -70,4 +70,4 @@ parse:
- torrentId - torrentId
match: match:
torrenturl: "{{ .baseUrl }}torrent/download/auto.{{ .torrentId }}.{{ .rsskey }}" torrenturl: "/torrent/download/auto.{{ .torrentId }}.{{ .rsskey }}"

View file

@ -5,7 +5,7 @@ identifier: bithdtv
description: Bit-HDTV (BHDTV) is a specialized HD tracker in movies and TV with so many daily uploads. description: Bit-HDTV (BHDTV) is a specialized HD tracker in movies and TV with so many daily uploads.
language: en-us language: en-us
urls: urls:
- https://www.bit-hdtv.com - https://www.bit-hdtv.com/
privacy: private privacy: private
protocol: torrent protocol: torrent
supports: supports:
@ -48,13 +48,13 @@ irc:
label: NickServ Password label: NickServ Password
help: NickServ password help: NickServ password
parse: parse:
type: single type: single
lines: lines:
- test: - test:
- "New torrent: Fear.the.walking.bee.s01e01.720p.WEB.h264-lemoncakes | Cat.: TV | WEB-DL | 720p | Uploader: ze0s | https://www.bit-hdtv.com/details.php?id=448412837123" - "New torrent: Fear.the.walking.bee.s01e01.720p.WEB.h264-lemoncakes | Cat.: TV | WEB-DL | 720p | Uploader: ze0s | https://www.bit-hdtv.com/details.php?id=448412837123"
- "New torrent: Y.r.u.there.2022.1080p.BluRay.DDP5.1.x264-egg | Cat.: Movies | Encode x264 | 1080p | Uploader: Anonymous | https://www.bit-hdtv.com/details.php?id=69" - "New torrent: Y.r.u.there.2022.1080p.BluRay.DDP5.1.x264-egg | Cat.: Movies | Encode x264 | 1080p | Uploader: Anonymous | https://www.bit-hdtv.com/details.php?id=69"
pattern: 'New torrent: (.*) \|\s*Cat.: ([^\|]*) \| .* Uploader: (.*) \| (https?\:\/\/[^\/]+).*id=(\d+)' pattern: 'New torrent: (.*) \|\s*Cat.: ([^\|]*) \| .* Uploader: (.*) \| (https?\:\/\/[^\/]+\/).*id=(\d+)'
vars: vars:
- torrentName - torrentName
- category - category
@ -63,4 +63,4 @@ parse:
- torrentId - torrentId
match: match:
torrenturl: "{{ .baseUrl }}/rssdownload.php?id={{ .torrentId }}&passkey={{ .passkey }}" torrenturl: "/rssdownload.php?id={{ .torrentId }}&passkey={{ .passkey }}"

View file

@ -47,14 +47,14 @@ irc:
label: NickServ Password label: NickServ Password
help: NickServ password help: NickServ password
parse: parse:
type: single type: single
lines: lines:
- test: - test:
- "[XXX » HD] Some.Porno.22.08.16.Famous.Actress.XXX.1080p.MP4-GROUP [ 3,00 GB | Pred 2022-08-16 08:47:31 (GMT) | URL: https://bittorrentfiles.me/details.php?id=0000000 ]" - "[XXX » HD] Some.Porno.22.08.16.Famous.Actress.XXX.1080p.MP4-GROUP [ 3,00 GB | Pred 2022-08-16 08:47:31 (GMT) | URL: https://bittorrentfiles.me/details.php?id=0000000 ]"
- "[Music » Single] [Dance Hall] Artist-Album-WEB-2021-GROUP [ 63,09 MB | Pred 2022-08-16 08:58:06 (GMT) | URL: https://bittorrentfiles.me/details.php?id=0000000 ]" - "[Music » Single] [Dance Hall] Artist-Album-WEB-2021-GROUP [ 63,09 MB | Pred 2022-08-16 08:58:06 (GMT) | URL: https://bittorrentfiles.me/details.php?id=0000000 ]"
- "[Sports » HD] Sports.League.2022.08.15.Team1.vs.Team2.720p.WEB.h264-GROUP [ 6,26 GB | Pred 2022-08-16 08:46:25 (GMT) | URL: https://bittorrentfiles.me/details.php?id=0000000 ]" - "[Sports » HD] Sports.League.2022.08.15.Team1.vs.Team2.720p.WEB.h264-GROUP [ 6,26 GB | Pred 2022-08-16 08:46:25 (GMT) | URL: https://bittorrentfiles.me/details.php?id=0000000 ]"
pattern: '\[(.*?)\] (?:\[(.*)\] )?(.*) \[ ([\d\.,]+ \w+) \| Pred .+ \| URL\: (https?\:\/\/[^\/]+)\/.*[&\?]id=(\d+) \]' pattern: '\[(.*?)\] (?:\[(.*)\] )?(.*) \[ ([\d\.,]+ \w+) \| Pred .+ \| URL\: (https?\:\/\/[^\/]+\/).*[&\?]id=(\d+) \]'
vars: vars:
- category - category
- tags - tags
@ -64,4 +64,4 @@ parse:
- torrentId - torrentId
match: match:
torrenturl: "{{ .baseUrl }}/download.php?torrent={{ .torrentId }}&k={{ .rsskey }}&ssl=1" torrenturl: "/download.php?torrent={{ .torrentId }}&k={{ .rsskey }}&ssl=1"

View file

@ -72,7 +72,7 @@ irc:
label: NickServ Password label: NickServ Password
help: NickServ password help: NickServ password
parse: parse:
type: multi type: multi
lines: lines:
- test: - test:
@ -96,10 +96,10 @@ parse:
- preTime - preTime
- test: - test:
- "[ https://XXXXXXXXX/torrents.php?id=7338 / https://XXXXXXXXX/torrents.php?action=download&id=9116 ]" - "[ https://XXXXXXXXX/torrents.php?id=7338 / https://XXXXXXXXX/torrents.php?action=download&id=9116 ]"
pattern: ^\[ .* \/ (https?:\/\/.*id=(\d+)) \] pattern: \[ .* \/ (https?:\/\/.*\/).+id=(\d+) \]
vars: vars:
- baseUrl - baseUrl
- torrentId - torrentId
match: match:
torrenturl: "{{ .baseUrl }}&authkey={{ .authkey }}&torrent_pass={{ .torrent_pass }}" torrenturl: "/torrents.php?action=download&id={{ .torrentId }}&authkey={{ .authkey }}&torrent_pass={{ .torrent_pass }}"

View file

@ -54,7 +54,7 @@ irc:
label: Invite command label: Invite command
help: Invite auth with DBBot. Replace IRCKEY with your key. help: Invite auth with DBBot. Replace IRCKEY with your key.
parse: parse:
type: single type: single
lines: lines:
- test: - test:
@ -72,4 +72,4 @@ parse:
- freeleech - freeleech
match: match:
torrenturl: "{{ .baseUrl }}torrent/download/{{ .torrentId }}.{{ .passkey }}" torrenturl: "/torrent/download/{{ .torrentId }}.{{ .passkey }}"

View file

@ -5,7 +5,7 @@ identifier: digitalcore
description: DigitalCore (DC) is a private torrent tracker for General / 0 Day. description: DigitalCore (DC) is a private torrent tracker for General / 0 Day.
language: en-us language: en-us
urls: urls:
- https://digitalcore.club - https://digitalcore.club/
privacy: private privacy: private
protocol: torrent protocol: torrent
supports: supports:
@ -54,12 +54,12 @@ irc:
label: Invite command label: Invite command
help: Invite auth with Endor. Replace USERNAME and IRCKEY help: Invite auth with Endor. Replace USERNAME and IRCKEY
parse: parse:
type: single type: single
lines: lines:
- test: - test:
- "NEW TORRENT in Movies/XviD :: This.is.my.Movie.2019.BRRip.XviD.AC3-iND :: https://digitalcore.club/api/v1/torrents/download/00000" - "NEW TORRENT in Movies/XviD :: This.is.my.Movie.2019.BRRip.XviD.AC3-iND :: https://digitalcore.club/api/v1/torrents/download/00000"
pattern: '^NEW.TORRENT.in.(.*?).::.(.*?).::.(.*)\/([0-9a-zA-Z]+)' pattern: 'NEW TORRENT in (.+) :: (.+) :: (https:\/\/.+\/).+\/([0-9a-zA-Z]+)'
vars: vars:
- category - category
- torrentName - torrentName
@ -67,4 +67,4 @@ parse:
- torrentId - torrentId
match: match:
torrenturl: "{{ .baseUrl }}/{{ .torrentId }}/{{ .passkey }}" torrenturl: "/api/v1/torrents/download/{{ .torrentId }}/{{ .passkey }}"

View file

@ -5,7 +5,8 @@ identifier: emp
description: Empornium (EMP) is a private torrent tracker for XXX description: Empornium (EMP) is a private torrent tracker for XXX
language: en-us language: en-us
urls: urls:
- https://www.empornium.is - https://www.empornium.is/
- https://www.empornium.sx/
privacy: private privacy: private
protocol: torrent protocol: torrent
supports: supports:
@ -53,12 +54,12 @@ irc:
label: NickServ Password label: NickServ Password
help: NickServ password help: NickServ password
parse: parse:
type: single type: single
lines: lines:
- test: - test:
- "Some long funny title - Size: 2.54 GiB - Uploader: uploader1 - Tags: tag1,tag2 - https://www.empornium.is/torrents.php?torrentid=000000" - "Some long funny title - Size: 2.54 GiB - Uploader: uploader1 - Tags: tag1,tag2 - https://www.empornium.is/torrents.php?torrentid=000000"
pattern: '(.*) - Size: (.*) - Uploader: (.*) - Tags: (.*) - (https:\/\/.*torrents\.php\?)torrentid=(.*)' pattern: '(.*) - Size: (.+) - Uploader: (.+) - Tags: (.*) - (https:\/\/.*\/)torrents\.php\?torrentid=(\d+)'
vars: vars:
- torrentName - torrentName
- torrentSize - torrentSize
@ -68,4 +69,4 @@ parse:
- torrentId - torrentId
match: match:
torrenturl: "{{ .baseUrl }}action=download&id={{ .torrentId }}&authkey={{ .authkey }}&torrent_pass={{ .torrent_pass }}" torrenturl: "/torrents.php?action=download&id={{ .torrentId }}&authkey={{ .authkey }}&torrent_pass={{ .torrent_pass }}"

View file

@ -5,7 +5,7 @@ identifier: enthralled
description: Enthralled (ENT) is a private torrent tracker for XXX description: Enthralled (ENT) is a private torrent tracker for XXX
language: en-us language: en-us
urls: urls:
- https://enthralled.me - https://enthralled.me/
privacy: private privacy: private
protocol: torrent protocol: torrent
supports: supports:
@ -53,12 +53,12 @@ irc:
label: NickServ Password label: NickServ Password
help: NickServ password help: NickServ password
parse: parse:
type: single type: single
lines: lines:
- test: - test:
- "Some release - Size: 559.06 MiB - Uploader: anon - Tags: worship,other - https://www.enthralled.me/torrents.php?torrentid=0000" - "Some release - Size: 559.06 MiB - Uploader: anon - Tags: worship,other - https://www.enthralled.me/torrents.php?torrentid=0000"
pattern: '(.*) - Size: (.*) - Uploader: (.*) - Tags: (.*?) - (https://.*)/torrents.php\?torrentid=(.*)' pattern: '(.*) - Size: (.+) - Uploader: (.+) - Tags: (.*?) - (https://.+\/)torrents.php\?torrentid=(\d+)'
vars: vars:
- torrentName - torrentName
- torrentSize - torrentSize
@ -68,4 +68,4 @@ parse:
- torrentId - torrentId
match: match:
torrenturl: "{{ .baseUrl }}/torrents.php?action=download&id={{ .torrentId }}&authkey={{ .authkey }}&torrent_pass={{ .torrent_pass }}" torrenturl: "/torrents.php?action=download&id={{ .torrentId }}&authkey={{ .authkey }}&torrent_pass={{ .torrent_pass }}"

View file

@ -5,7 +5,7 @@ identifier: fl
description: FileList (FL) is a ROMANIAN private torrent tracker for MOVIES / TV / GENERAL description: FileList (FL) is a ROMANIAN private torrent tracker for MOVIES / TV / GENERAL
language: en-us language: en-us
urls: urls:
- https://filelist.io - https://filelist.io/
privacy: private privacy: private
protocol: torrent protocol: torrent
supports: supports:
@ -47,7 +47,7 @@ irc:
label: NickServ Password label: NickServ Password
help: NickServ password help: NickServ password
parse: parse:
type: single type: single
lines: lines:
- test: - test:
@ -66,6 +66,6 @@ parse:
- uploader - uploader
match: match:
torrenturl: "{{ .baseUrl }}download.php?id={{ .torrentId }}&file={{ .torrentName }}.torrent&passkey={{ .passkey }}" torrenturl: "/download.php?id={{ .torrentId }}&file={{ .torrentName }}.torrent&passkey={{ .passkey }}"
encode: encode:
- torrentName - torrentName

View file

@ -50,7 +50,7 @@ irc:
label: NickServ Password label: NickServ Password
help: NickServ password help: NickServ password
parse: parse:
type: single type: single
lines: lines:
- test: - test:
@ -68,6 +68,6 @@ parse:
- torrentName - torrentName
match: match:
torrenturl: "https://www.{{ .baseUrl }}/rss/torrent.php/{{ .torrentId }}/{{ .uid }}/{{ .passkey }}/{{ .torrentName }}.torrent" torrenturl: "/rss/torrent.php/{{ .torrentId }}/{{ .uid }}/{{ .passkey }}/{{ .torrentName }}.torrent"
encode: encode:
- torrentName - torrentName

View file

@ -79,7 +79,7 @@ irc:
label: Invite command label: Invite command
help: Invite auth with Vertigo. Replace USERNAME and IRCKEY. help: Invite auth with Vertigo. Replace USERNAME and IRCKEY.
parse: parse:
type: single type: single
lines: lines:
- test: - test:
@ -98,4 +98,4 @@ parse:
- tags - tags
match: match:
torrenturl: "{{ .baseUrl }}torrents.php?action=download&id={{ .torrentId }}&authkey={{ .authkey }}&torrent_pass={{ .torrent_pass }}" torrenturl: "/torrents.php?action=download&id={{ .torrentId }}&authkey={{ .authkey }}&torrent_pass={{ .torrent_pass }}"

View file

@ -5,7 +5,7 @@ identifier: hd-space
description: HD-Space (HDS) is a Private Torrent Tracker for HD MOVIES / TV description: HD-Space (HDS) is a Private Torrent Tracker for HD MOVIES / TV
language: en-us language: en-us
urls: urls:
- https://hd-space.org - https://hd-space.org/
privacy: private privacy: private
protocol: torrent protocol: torrent
supports: supports:
@ -47,7 +47,7 @@ irc:
label: NickServ Password label: NickServ Password
help: NickServ password help: NickServ password
parse: parse:
type: single type: single
lines: lines:
- test: - test:
@ -63,6 +63,6 @@ parse:
- torrentId - torrentId
match: match:
torrenturl: "{{ .baseUrl }}download.php?id={{ .torrentId }}&f={{ .torrentName }}.torrent&rsspid={{ .rsskey }}" torrenturl: "/download.php?id={{ .torrentId }}&f={{ .torrentName }}.torrent&rsspid={{ .rsskey }}"
encode: encode:
- torrentName - torrentName

View file

@ -6,7 +6,7 @@ description: HD-Torrents (HD-T) is a private torrent tracker for HD MOVIES / TV
language: en-us language: en-us
urls: urls:
- https://hd-torrents.org/ - https://hd-torrents.org/
- https://hdts.ru - https://hdts.ru/
privacy: private privacy: private
protocol: torrent protocol: torrent
supports: supports:
@ -53,7 +53,7 @@ irc:
label: NickServ Password label: NickServ Password
help: NickServ password help: NickServ password
parse: parse:
type: single type: single
lines: lines:
- test: - test:
@ -67,6 +67,6 @@ parse:
- torrentId - torrentId
match: match:
torrenturl: "{{ .baseUrl }}rss/?action=download&key={{ .key }}&token={{ .token }}&hash={{ .torrentId }}&title={{ .torrentName }}" torrenturl: "/rss/?action=download&key={{ .key }}&token={{ .token }}&hash={{ .torrentId }}&title={{ .torrentName }}"
encode: encode:
- torrentName - torrentName

View file

@ -54,7 +54,7 @@ irc:
label: Invite command label: Invite command
help: Invite auth with the key from https://hdbits.org/bot_invite.php. Replace IRCKEY. help: Invite auth with the key from https://hdbits.org/bot_invite.php. Replace IRCKEY.
parse: parse:
type: single type: single
lines: lines:
- test: - test:
@ -74,4 +74,4 @@ parse:
- torrentId - torrentId
match: match:
torrenturl: "{{ .baseUrl }}download.php?id={{ .torrentId }}&passkey={{ .passkey }}" torrenturl: "/download.php?id={{ .torrentId }}&passkey={{ .passkey }}"

View file

@ -58,7 +58,7 @@ irc:
label: Invite command label: Invite command
help: "Replace IRCKEY with: Edit Profile -> Access Settings -> IRC Key" help: "Replace IRCKEY with: Edit Profile -> Access Settings -> IRC Key"
parse: parse:
type: multi type: multi
lines: lines:
- test: - test:
@ -72,7 +72,7 @@ parse:
- torrentSize - torrentSize
- test: - test:
- "Link: https://hebits.net/torrents.php?torrentid=80081" - "Link: https://hebits.net/torrents.php?torrentid=80081"
pattern: '^Link: https?\:\/\/?[w{3}.]*([^\/]+).*(?:&amp;|\?)torrentid=(\d+)' pattern: '^Link: (https?\:\/\/?[w{3}.]*[^\/]+\/).+torrentid=(\d+)'
vars: vars:
- baseUrl - baseUrl
- torrentId - torrentId
@ -85,4 +85,4 @@ parse:
- torrentName - torrentName
match: match:
torrenturl: "https://{{ .baseUrl }}/torrents.php?action=download&id={{ .torrentId }}&authkey={{ .authkey }}&torrent_pass={{ .passkey }}" torrenturl: "/torrents.php?action=download&id={{ .torrentId }}&authkey={{ .authkey }}&torrent_pass={{ .passkey }}"

View file

@ -5,7 +5,7 @@ identifier: huno
description: Hawke-UNO (HUNO) is a private torrent tracker for MOVIES / TV. description: Hawke-UNO (HUNO) is a private torrent tracker for MOVIES / TV.
language: en-us language: en-us
urls: urls:
- https://hawke.uno - https://hawke.uno/
privacy: private privacy: private
protocol: torrent protocol: torrent
supports: supports:
@ -47,13 +47,13 @@ irc:
label: NickServ Password label: NickServ Password
help: NickServ password help: NickServ password
parse: parse:
type: single type: single
lines: lines:
- test: - test:
- "New in [Movie]: Old Movie (1981) (1080p BluRay x265 SDR DD 2.0 English - group1) [4.5 GiB] [FL: No] [INTERNAL: Yes] [https://hawke.uno/torrents/0000] by: [anon]" - "New in [Movie]: Old Movie (1981) (1080p BluRay x265 SDR DD 2.0 English - group1) [4.5 GiB] [FL: No] [INTERNAL: Yes] [https://hawke.uno/torrents/0000] by: [anon]"
- "New in [TV]: Popular show (2022) S01E09 (1080p DSNP WEB-DL x265 SDR DDP Atmos 5.1 English - GROUP)[REPACK] [955.97 MiB] [FL: Yes] [INTERNAL: Yes] [https://hawke.uno/torrents/0000] by: [uploader]" - "New in [TV]: Popular show (2022) S01E09 (1080p DSNP WEB-DL x265 SDR DDP Atmos 5.1 English - GROUP)[REPACK] [955.97 MiB] [FL: Yes] [INTERNAL: Yes] [https://hawke.uno/torrents/0000] by: [uploader]"
pattern: 'New in \[(.+)\]: (.+)(?:\[(?:REPACK\d?|PROPER)\])? \[(.+)\] \[FL: (Yes|No)\] \[INTERNAL: (Yes|No)\] \[(https:\/\/.+)\/torrents\/(\d+)\] by: \[(.+)\]' pattern: 'New in \[(.+)\]: (.+)(?:\[(?:REPACK\d?|PROPER)\])? \[(.+)\] \[FL: (Yes|No)\] \[INTERNAL: (Yes|No)\] \[(https:\/\/.+\/)torrents\/(\d+)\] by: \[(.+)\]'
vars: vars:
- category - category
- torrentName - torrentName
@ -65,4 +65,4 @@ parse:
- uploader - uploader
match: match:
torrenturl: "{{ .baseUrl }}/torrent/download/{{ .torrentId }}.{{ .rsskey }}" torrenturl: "/torrent/download/{{ .torrentId }}.{{ .rsskey }}"

View file

@ -5,7 +5,7 @@ identifier: immortalseed
description: ImmortalSeed (iS) is a Private Torrent Tracker for MOVIES / TV / GENERAL description: ImmortalSeed (iS) is a Private Torrent Tracker for MOVIES / TV / GENERAL
language: en-us language: en-us
urls: urls:
- https://immortalseed.me - https://immortalseed.me/
privacy: private privacy: private
protocol: torrent protocol: torrent
supports: supports:
@ -55,7 +55,7 @@ irc:
label: Invite command label: Invite command
help: Invite auth with immortal. Replace USERNAME and PASSKEY. help: Invite auth with immortal. Replace USERNAME and PASSKEY.
parse: parse:
type: single type: single
lines: lines:
- test: - test:
@ -71,4 +71,4 @@ parse:
- torrentId - torrentId
match: match:
torrenturl: "{{ .baseUrl }}download.php?type=rss&secret_key={{ .passkey }}&id={{ .torrentId }}" torrenturl: "/download.php?type=rss&secret_key={{ .passkey }}&id={{ .torrentId }}"

View file

@ -5,7 +5,7 @@ identifier: romanianmetaltorrents
description: Romanian Metal Torrents (RMT) is a private torrent tracker for METAL MUSIC. description: Romanian Metal Torrents (RMT) is a private torrent tracker for METAL MUSIC.
language: en-us language: en-us
urls: urls:
- https://metal.iplay.ro - https://metal.iplay.ro/
privacy: private privacy: private
protocol: torrent protocol: torrent
supports: supports:
@ -47,7 +47,7 @@ irc:
label: NickServ Password label: NickServ Password
help: NickServ password help: NickServ password
parse: parse:
type: single type: single
lines: lines:
- test: - test:
@ -63,4 +63,4 @@ parse:
- uploader - uploader
match: match:
torrenturl: "{{ .baseUrl }}/download2.php?id={{ .torrentId }}&passkey={{ .passkey }}" torrenturl: "/download2.php?id={{ .torrentId }}&passkey={{ .passkey }}"

View file

@ -7,6 +7,15 @@ language: en-us
urls: urls:
- https://iptorrents.com/ - https://iptorrents.com/
- https://iptorrents.me/ - https://iptorrents.me/
- https://nemo.iptorrents.com/
- https://ipt.getcrazy.me/
- https://ipt.findnemo.net/
- https://ipt.beelyrics.net/
- https://ipt.venom.global/
- https://ipt.workisboring.net/
- https://ipt.lol/
- https://ipt.cool/
- https://ipt.world/
privacy: private privacy: private
protocol: torrent protocol: torrent
supports: supports:
@ -49,13 +58,13 @@ irc:
label: NickServ Password label: NickServ Password
help: NickServ password help: NickServ password
parse: parse:
type: single type: single
lines: lines:
- test: - test:
- "[Movies/XviD] The Movie 2010 DVDRip XviD-GROUP FREELEECH - http://www.iptorrents.com/details.php?id=000000 - 716.219 MB" - "[Movies/XviD] The Movie 2010 DVDRip XviD-GROUP FREELEECH - http://www.iptorrents.com/details.php?id=000000 - 716.219 MB"
- "[Movies/XviD] The Movie 2010 DVDRip XviD-GROUP - http://www.iptorrents.com/details.php?id=000000 - 716.219 MB" - "[Movies/XviD] The Movie 2010 DVDRip XviD-GROUP - http://www.iptorrents.com/details.php?id=000000 - 716.219 MB"
pattern: '^\[([^\]]*)] (.*?)\s*(FREELEECH)*\s*-\s+(https?\:\/\/[^\/]+).*[&\?]id=(\d+)\s*- (.*)' pattern: '\[(.+)] (.*?)\s*(FREELEECH)* - (https?\:\/\/.+\/).+id=(\d+) - (.*)'
vars: vars:
- category - category
- torrentName - torrentName
@ -65,6 +74,6 @@ parse:
- torrentSize - torrentSize
match: match:
torrenturl: "{{ .baseUrl }}/download.php/{{ .torrentId }}/{{ .torrentName }}.torrent?torrent_pass={{ .passkey }}" torrenturl: "/download.php/{{ .torrentId }}/{{ .torrentName }}.torrent?torrent_pass={{ .passkey }}"
encode: encode:
- torrentName - torrentName

View file

@ -5,7 +5,7 @@ identifier: milkie
description: Milkie is a private torrent tracker for GENERAL. description: Milkie is a private torrent tracker for GENERAL.
language: en-us language: en-us
urls: urls:
- https://www.milkie.cc - https://www.milkie.cc/
privacy: private privacy: private
protocol: torrent protocol: torrent
supports: supports:
@ -50,7 +50,7 @@ irc:
label: NickServ Password label: NickServ Password
help: NickServ password help: NickServ password
parse: parse:
type: single type: single
lines: lines:
- test: - test:
@ -64,6 +64,6 @@ parse:
- torrentId - torrentId
match: match:
torrenturl: "{{ .baseUrl }}api/v1/torrents/{{ .torrentId }}/torrent?key={{ .apikey }}" torrenturl: "/api/v1/torrents/{{ .torrentId }}/torrent?key={{ .apikey }}"
encode: encode:
- apikey - apikey

View file

@ -5,7 +5,7 @@ identifier: morethantv
description: MoreThanTv (MTV) is a torrent tracker for Series and Movies. description: MoreThanTv (MTV) is a torrent tracker for Series and Movies.
language: en-us language: en-us
urls: urls:
- https://www.morethantv.me - https://www.morethantv.me/
privacy: private privacy: private
protocol: torrent protocol: torrent
supports: supports:
@ -53,12 +53,12 @@ irc:
label: NickServ Password label: NickServ Password
help: NickServ password help: NickServ password
parse: parse:
type: single type: single
lines: lines:
- test: - test:
- "TV.Show.2008.720p.BluRay.DTS.x264-TEST - Size: 6.56 GiB - Uploader: Test - Tags: autoup,h264,hd,dts.audio,bluray,720p,p2p.group.release,Test.release,hd.movie - https://www.morethantv.me/torrents.php?torrentid=000000" - "TV.Show.2008.720p.BluRay.DTS.x264-TEST - Size: 6.56 GiB - Uploader: Test - Tags: autoup,h264,hd,dts.audio,bluray,720p,p2p.group.release,Test.release,hd.movie - https://www.morethantv.me/torrents.php?torrentid=000000"
pattern: '^(.*?) - Size: ([0-9]+?.*?) - Uploader: (.*?) - Tags: (.*(hd.episode|hd.season|sd.episode|sd.season|sd.movie|hd.movie)) - (https?:\/\/.*torrents.php\?)torrentid=(.*)$' pattern: '(.+) - Size: (.+) - Uploader: (.+) - Tags: (.+(hd.episode|hd.season|sd.episode|sd.season|sd.movie|hd.movie)) - (https?:\/\/.+\/)torrents.php\?torrentid=(\d+)'
vars: vars:
- torrentName - torrentName
- torrentSize - torrentSize
@ -69,4 +69,4 @@ parse:
- torrentId - torrentId
match: match:
torrenturl: "{{ .baseUrl }}action=download&id={{ .torrentId }}&authkey={{ .authkey }}&torrent_pass={{ .torrent_pass }}" torrenturl: "/torrents.php?action=download&id={{ .torrentId }}&authkey={{ .authkey }}&torrent_pass={{ .torrent_pass }}"

View file

@ -5,7 +5,7 @@ identifier: myanonamouse
description: MyAnonaMouse (MAM) is a large ebook and audiobook tracker. description: MyAnonaMouse (MAM) is a large ebook and audiobook tracker.
language: en-us language: en-us
urls: urls:
- https://www.myanonamouse.net - https://www.myanonamouse.net/
privacy: private privacy: private
protocol: torrent protocol: torrent
supports: supports:
@ -47,7 +47,7 @@ irc:
label: NickServ Password label: NickServ Password
help: NickServ password help: NickServ password
parse: parse:
type: single type: single
lines: lines:
- test: - test:
@ -66,5 +66,5 @@ parse:
- freeleech - freeleech
match: match:
torrenturl: "{{ .baseUrl }}tor/download.php?tid={{ .torrentId }}" torrenturl: "/tor/download.php?tid={{ .torrentId }}"
torrentname: "{{ .torrentName }} by {{ .author }} [{{ .language }} / {{ .tags }}]" torrentname: "{{ .torrentName }} by {{ .author }} [{{ .language }} / {{ .tags }}]"

View file

@ -4,7 +4,7 @@ identifier: ncore
description: nCore description: nCore
language: en-us language: en-us
urls: urls:
- https://ncore.pro - https://ncore.pro/
privacy: private privacy: private
protocol: torrent protocol: torrent
supports: supports:
@ -53,7 +53,7 @@ irc:
label: Invite command label: Invite command
help: Invite auth with the key from https://ncore.pro/irc.php. Replace IRCKEY help: Invite auth with the key from https://ncore.pro/irc.php. Replace IRCKEY
parse: parse:
type: single type: single
lines: lines:
- test: - test:
@ -69,4 +69,4 @@ parse:
match: match:
# https://ncore.pro/torrents.php?action=download&id=0000&key=00000 # https://ncore.pro/torrents.php?action=download&id=0000&key=00000
torrenturl: "{{ .baseUrl }}download&id={{ .torrentId }}&key={{ .passkey }}" torrenturl: "/download&id={{ .torrentId }}&key={{ .passkey }}"

View file

@ -60,14 +60,14 @@ irc:
label: Invite command label: Invite command
help: Invite auth with Muffit. Replace USERNAME and IRCKEY. help: Invite auth with Muffit. Replace USERNAME and IRCKEY.
parse: parse:
type: single type: single
lines: lines:
- test: - test:
- "[Episodes] The Show - S02E08 [WebRip / x264 / MKV / 720p / HD / VLAD / The.Show.S02E08.Episode.Name.720p.ANPL.WEBRip.AAC2.0.x264-GROUP.mkv] [702.00 MB - Uploader: UPLOADER] - http://nebulance.io/torrents.php?id=000 [Tags: comedy,subtitles,cbs]" - "[Episodes] The Show - S02E08 [WebRip / x264 / MKV / 720p / HD / VLAD / The.Show.S02E08.Episode.Name.720p.ANPL.WEBRip.AAC2.0.x264-GROUP.mkv] [702.00 MB - Uploader: UPLOADER] - http://nebulance.io/torrents.php?id=000 [Tags: comedy,subtitles,cbs]"
- "[Seasons] Other Show - S10 [HDTV / x264 / MKV / MP4 / 480p / SD / BTN / Other.Show.S10.HDTV.x264-GROUP] [5.27 GB - Uploader: UPLOADER] - http://nebulance.io/torrents.php?id=0000 [Tags: comedy,subtitles,cbs]" - "[Seasons] Other Show - S10 [HDTV / x264 / MKV / MP4 / 480p / SD / BTN / Other.Show.S10.HDTV.x264-GROUP] [5.27 GB - Uploader: UPLOADER] - http://nebulance.io/torrents.php?id=0000 [Tags: comedy,subtitles,cbs]"
- "[Episode] Late Night with Show Host - 2021-01-20 [WebDl / h264 / MKV / 1080p / HD / Scene / GROUP / talk.show.2021.01.20.famous.person.1080p.web.h264-group.mkv] [2.22 GB - Uploader: Uploader1] - http://nebulance.io/torrents.php?id=000000 [Tags: episode,comedy,talk.show,nbc,autofill,subtitles,webdl,h264,mkv,1080p,hd,scene,group.release]" - "[Episode] Late Night with Show Host - 2021-01-20 [WebDl / h264 / MKV / 1080p / HD / Scene / GROUP / talk.show.2021.01.20.famous.person.1080p.web.h264-group.mkv] [2.22 GB - Uploader: Uploader1] - http://nebulance.io/torrents.php?id=000000 [Tags: episode,comedy,talk.show,nbc,autofill,subtitles,webdl,h264,mkv,1080p,hd,scene,group.release]"
pattern: '\[(.*?)\] (.*?) - (?:S.*|\d{4}-\d{2}-\d{2}) \[(.*) \/ (.*)\] \[(.*?) - Uploader: (.*?)\] - (https?:\/\/.*)id=(\d+) \[Tags: (.*)\]' pattern: '\[(.+)\] (.+) - .+ \[(.+) \/ (.+)\] \[(.+) - Uploader: (.+)\] - (https?:\/\/.+\/).+id=(\d+) \[Tags: (.*)\]'
vars: vars:
- category - category
- title - title
@ -80,4 +80,4 @@ parse:
- tags - tags
match: match:
torrenturl: "{{ .baseUrl }}action=download&id={{ .torrentId }}&authkey={{ .authkey }}&torrent_pass={{ .torrent_pass }}" torrenturl: "/torrents.php?action=download&id={{ .torrentId }}&authkey={{ .authkey }}&torrent_pass={{ .torrent_pass }}"

View file

@ -5,7 +5,7 @@ identifier: norbits
description: NorBits is a Norwegian Private site for MOVIES / TV / GENERAL description: NorBits is a Norwegian Private site for MOVIES / TV / GENERAL
language: nb-NO language: nb-NO
urls: urls:
- https://www.norbits.net - https://www.norbits.net/
privacy: private privacy: private
protocol: torrent protocol: torrent
supports: supports:
@ -47,7 +47,7 @@ irc:
label: NickServ Password label: NickServ Password
help: NickServ password help: NickServ password
parse: parse:
type: single type: single
lines: lines:
- test: - test:
@ -63,4 +63,4 @@ parse:
- torrentId - torrentId
match: match:
torrenturl: "{{ .baseUrl }}download.php?id={{ .torrentId }}&passkey={{ .passkey }}" torrenturl: "/download.php?id={{ .torrentId }}&passkey={{ .passkey }}"

View file

@ -68,7 +68,7 @@ irc:
# Audio # Audio
# Other # Other
parse: parse:
type: single type: single
lines: lines:
- test: - test:
@ -85,4 +85,4 @@ parse:
- tags - tags
match: match:
torrenturl: "{{ .baseUrl }}torrents.php?action=download&id={{ .torrentId }}&authkey={{ .authkey }}&torrent_pass={{ .torrent_pass }}" torrenturl: "/torrents.php?action=download&id={{ .torrentId }}&authkey={{ .authkey }}&torrent_pass={{ .torrent_pass }}"

View file

@ -54,13 +54,13 @@ irc:
label: Invite command label: Invite command
help: Invite auth with Hermes. Replace USERNAME and IRCKEY. help: Invite auth with Hermes. Replace USERNAME and IRCKEY.
parse: parse:
type: single type: single
lines: lines:
- test: - test:
- "TORRENT: That Artist - Albuum [2002] [Single] - FLAC / Lossless / WEB - 2000s,house,uk.garage,garage.house - https://orpheus.network/torrents.php?id=000000 / https://orpheus.network/torrents.php?action=download&id=0000000" - "TORRENT: That Artist - Albuum [2002] [Single] - FLAC / Lossless / WEB - 2000s,house,uk.garage,garage.house - https://orpheus.network/torrents.php?id=000000 / https://orpheus.network/torrents.php?action=download&id=0000000"
- "TORRENT: Something [2021] [Album] - FLAC / Lossless / CD - - https://orpheus.network/torrents.php?id=000000 / https://orpheus.network/torrents.php?action=download&id=0000000" - "TORRENT: Something [2021] [Album] - FLAC / Lossless / CD - - https://orpheus.network/torrents.php?id=000000 / https://orpheus.network/torrents.php?action=download&id=0000000"
pattern: 'TORRENT: (.*) \[(.+?)\] \[(.+?)\] - (.*) - \s*(.*) - https?:\/\/.* \/ (https?:\/\/.*id=\d+)' pattern: 'TORRENT: (.*) \[(.+?)\] \[(.+?)\] - (.*) - \s*(.*) - https?:\/\/.* \/ (https?:\/\/.+\/).+id=(\d+)'
vars: vars:
- torrentName - torrentName
- year - year
@ -68,6 +68,7 @@ parse:
- releaseTags - releaseTags
- tags - tags
- baseUrl - baseUrl
- torrentId
match: match:
torrenturl: "{{ .baseUrl }}&torrent_pass={{ .torrent_pass }}" torrenturl: "/torrents.php?action=download&id={{ .torrentId }}&torrent_pass={{ .torrent_pass }}"

View file

@ -5,7 +5,7 @@ identifier: pornbay
description: Pornbay (PB) is a private torrent tracker for XXX description: Pornbay (PB) is a private torrent tracker for XXX
language: en-us language: en-us
urls: urls:
- https://pornbay.org - https://pornbay.org/
privacy: private privacy: private
protocol: torrent protocol: torrent
supports: supports:
@ -53,13 +53,13 @@ irc:
label: NickServ Password label: NickServ Password
help: NickServ password help: NickServ password
parse: parse:
type: single type: single
lines: lines:
- test: - test:
- "[XXX-Cateogry] [SomeXXXSite] Wow So Much Come [2015-05-30, 3K, 1500p] [4.77 GB - Uploader: Tester] - https://pornbay.org/torrents.php?id=000000" - "[XXX-Cateogry] [SomeXXXSite] Wow So Much Come [2015-05-30, 3K, 1500p] [4.77 GB - Uploader: Tester] - https://pornbay.org/torrents.php?id=000000"
- "[XXX-Category-2] SomeXXXSite - Some Name [1.35 GB - Uploader: someUploader] - https://pornbay.org/torrents.php?id=000000" - "[XXX-Category-2] SomeXXXSite - Some Name [1.35 GB - Uploader: someUploader] - https://pornbay.org/torrents.php?id=000000"
pattern: '^\[(.*?)\] (.*) \[([0-9]+?.*?) - Uploader: (.*?)\] - (https://.*torrents.php\?)id=(.*)$' pattern: '\[(.+)\] (.*) \[([0-9]+?.*?) - Uploader: (.+)\] - (https:\/\/.+\/)torrents.php\?id=(\d+)'
vars: vars:
- category - category
- torrentName - torrentName
@ -69,4 +69,4 @@ parse:
- torrentId - torrentId
match: match:
torrenturl: "{{ .baseUrl }}action=download&id={{ .torrentId }}&authkey={{ .authkey }}&torrent_pass={{ .torrent_pass }}" torrenturl: "/torrents.php?action=download&id={{ .torrentId }}&authkey={{ .authkey }}&torrent_pass={{ .torrent_pass }}"

View file

@ -5,7 +5,7 @@ identifier: polishsource
description: PolishSource (PS) is a POLISH private torrent tracker for 0DAY / GENERAL. description: PolishSource (PS) is a POLISH private torrent tracker for 0DAY / GENERAL.
language: en-us language: en-us
urls: urls:
- https://polishsource.cz - https://polishsource.cz/
privacy: private privacy: private
protocol: torrent protocol: torrent
supports: supports:
@ -54,22 +54,22 @@ irc:
label: Invite command label: Invite command
help: Invite auth with PS-Info. Replace IRCKEY with your IRC key. help: Invite auth with PS-Info. Replace IRCKEY with your IRC key.
parse:
parse:
type: single type: single
lines: lines:
- test: - test:
- "Some.Show.S09E01.HDTV.x264-GROUP > TV/SD > 359.285 MB / 2 F > [ http://polishsource.cz/details.php?id=000000 ]-[ 5h 25min 15sec after pre ]" - "Some.Show.S09E01.HDTV.x264-GROUP > TV/SD > 359.285 MB / 2 F > [ http://polishsource.cz/details.php?id=000000 ]-[ 5h 25min 15sec after pre ]"
- "Some.Movie.2011.DVDRip.x264-GROUP2 > Movies/x264 (Documentary) > 563.296 MB / 2 F > [ http://polishsource.cz/details.php?id=000000 ]-[ 2min 48sec after pre ]" - "Some.Movie.2011.DVDRip.x264-GROUP2 > Movies/x264 (Documentary) > 563.296 MB / 2 F > [ http://polishsource.cz/details.php?id=000000 ]-[ 2min 48sec after pre ]"
pattern: '(.*)\s>\s(.*)\s>\s(.*) \/.*>\s*\[ https?\:\/\/([^\/]+)\/.*[&?]id=(\d+)\s\](?:-\[ (.*) \])?' pattern: '(.*) > (.*) > (.*) \/.*>\s*\[ (https?\:\/\/.+\/).*[&?]id=(\d+)\s\](?:-\[ (.*) \])?'
vars: vars:
- torrentName - torrentName
- category - category
- torrentSize - torrentSize
- baseUrl - baseUrl
- torrentId - torrentId
- preTime
match: match:
torrenturl: "https://{{ .baseUrl }}/downloadssl.php?id={{ .torrentId }}&torr={{ .torrentName }}.torrent&passkey={{ .passkey }}" torrenturl: "/downloadssl.php?id={{ .torrentId }}&torr={{ .torrentName }}.torrent&passkey={{ .passkey }}"
encode: encode:
- torrentName - torrentName

View file

@ -5,7 +5,7 @@ identifier: polishtracker
description: PolishTracker (PT) is a POLISH private torrent tracker for 0DAY / GENERAL. description: PolishTracker (PT) is a POLISH private torrent tracker for 0DAY / GENERAL.
language: en-us language: en-us
urls: urls:
- https://pte.nu - https://pte.nu/
privacy: private privacy: private
protocol: torrent protocol: torrent
supports: supports:
@ -54,14 +54,14 @@ irc:
label: Invite command label: Invite command
help: Invite auth with PT-BOT. Replace IRCKEY with your IRC key. help: Invite auth with PT-BOT. Replace IRCKEY with your IRC key.
parse: parse:
type: single type: single
lines: lines:
- test: - test:
- "::: PolishTracker ::: Torrent ( Some.Movie.2017.PLSUB.1080p.BDRip.x264-GROUP ) || Kategoria: ( movies HD ) || Rozmiar: ( 2.14 GB ) || Link: ( https://pte.nu/torrents/000000 ) || Wiecej: ( http://www.filmweb.pl/film?id=000000 )" - "::: PolishTracker ::: Torrent ( Some.Movie.2017.PLSUB.1080p.BDRip.x264-GROUP ) || Kategoria: ( movies HD ) || Rozmiar: ( 2.14 GB ) || Link: ( https://pte.nu/torrents/000000 ) || Wiecej: ( http://www.filmweb.pl/film?id=000000 )"
- "::: PolishTracker ::: Torrent ( Some.Other.Movie.1985.iNTERNAL.BDRip.x264-GROUP ) || Kategoria: ( movies SD ) || Rozmiar: ( 1.15 GB ) || Link: ( https://pte.nu/torrents/000000 )" - "::: PolishTracker ::: Torrent ( Some.Other.Movie.1985.iNTERNAL.BDRip.x264-GROUP ) || Kategoria: ( movies SD ) || Rozmiar: ( 1.15 GB ) || Link: ( https://pte.nu/torrents/000000 )"
- "::: PolishTracker ::: Torrent ( Some.Other.Movie.1985.iNTERNAL.720p.BluRay.x264-GROUP ) || Kategoria: ( movies HD ) || Rozmiar: ( 5.02 GB ) || Link: ( https://pte.nu/torrents/000000 )" - "::: PolishTracker ::: Torrent ( Some.Other.Movie.1985.iNTERNAL.720p.BluRay.x264-GROUP ) || Kategoria: ( movies HD ) || Rozmiar: ( 5.02 GB ) || Link: ( https://pte.nu/torrents/000000 )"
pattern: '::: PolishTracker ::: Torrent \( (.*) \) \|\| Kategoria: \( (.*) \) \|\| Rozmiar: \( (.*) \) \|\| Link: \( (https://.*)/torrents/(\d+) \)' pattern: '::: PolishTracker ::: Torrent \( (.+) \) \|\| Kategoria: \( (.+) \) \|\| Rozmiar: \( (.+) \) \|\| Link: \( (https:\/\/.+\/)torrents\/(\d+) \)'
vars: vars:
- torrentName - torrentName
- category - category
@ -70,4 +70,4 @@ parse:
- torrentId - torrentId
match: match:
torrenturl: "{{ .baseUrl }}/downrss/{{ .rsskey }}/{{ .torrentId }}" torrenturl: "/downrss/{{ .rsskey }}/{{ .torrentId }}"

View file

@ -48,15 +48,15 @@ irc:
label: NickServ Password label: NickServ Password
help: NickServ password help: NickServ password
parse: parse:
type: single type: single
lines: lines:
- test: - test:
- "tehFire: [Applications|Windows] Chen went to the Mall :: preGAP: 1m and 32s :: https://pretome.info/details.php?id=696969" - "tehFire: [Applications|Windows] Chen went to the Mall :: preGAP: 1m and 32s :: https://pretome.info/details.php?id=696969"
- "[Movies|x264] Orlando.Bloom.Had.A.Cow-ze0s :: preGAP: P2P source :: https://pretome.info/details.php?id=646321" - "[Movies|x264] Orlando.Bloom.Had.A.Cow-GROUP :: preGAP: P2P source :: https://pretome.info/details.php?id=646321"
- "tehFIRE: [TV|XviD] Royal.Institution.Christmas.Lectures.2009.Part2.WS.PDTV.XviD-WATERS :: preGAP: 1m and 9s :: https://pretome.info/details.php?id=127107" - "tehFIRE: [TV|XviD] Royal.Institution.Christmas.Lectures.2009.Part2.WS.PDTV.XviD-WATERS :: preGAP: 1m and 9s :: https://pretome.info/details.php?id=127107"
- "tehFIRE: [TV|x264] Newsreaders.S01E05.HDTV.x264-2HD https://pretome.info/details.php?id=333951" - "tehFIRE: [TV|x264] Newsreaders.S01E05.HDTV.x264-2HD https://pretome.info/details.php?id=333951"
pattern: '\[([^\]]+)\] ([^:]+)(?: :: [^:]+:.* :: )?(https?\:\/\/[^\/]+).*id=(\d+)' pattern: '\[([^\]]+)\] ([^:]+)(?: :: [^:]+:.* :: )?(https?\:\/\/.+\/).*id=(\d+)'
vars: vars:
- category - category
- torrentName - torrentName
@ -64,6 +64,6 @@ parse:
- torrentId - torrentId
match: match:
torrenturl: "{{ .baseUrl }}/download.php/{{ .torrentId }}/{{ .rsskey }}/{{ .torrentName }}.torrent" torrenturl: "/download.php/{{ .torrentId }}/{{ .rsskey }}/{{ .torrentName }}.torrent"
encode: encode:
- torrentName - torrentName

View file

@ -5,7 +5,7 @@ identifier: ptp
description: PassThePopcorn (PTP) is a private torrent tracker for MOVIES description: PassThePopcorn (PTP) is a private torrent tracker for MOVIES
language: en-us language: en-us
urls: urls:
- https://passthepopcorn.me - https://passthepopcorn.me/
privacy: private privacy: private
protocol: torrent protocol: torrent
supports: supports:
@ -89,7 +89,7 @@ irc:
label: Invite command label: Invite command
help: Invite auth with Hummingbird. Replace USERNAME and IRCKEY. help: Invite auth with Hummingbird. Replace USERNAME and IRCKEY.
parse: parse:
type: single type: single
lines: lines:
- test: - test:
@ -104,4 +104,4 @@ parse:
- tags - tags
match: match:
torrenturl: "https://passthepopcorn.me/torrents.php?action=download&id={{ .torrentId }}&authkey={{ .authkey }}&torrent_pass={{ .torrent_pass }}" torrenturl: "/torrents.php?action=download&id={{ .torrentId }}&authkey={{ .authkey }}&torrent_pass={{ .torrent_pass }}"

View file

@ -48,7 +48,7 @@ irc:
label: NickServ Password label: NickServ Password
help: NickServ password help: NickServ password
parse: parse:
type: single type: single
lines: lines:
- test: - test:
@ -63,7 +63,6 @@ parse:
- torrentId - torrentId
match: match:
torrenturl: "{{ .baseUrl }}rss/download/{{ .torrentId }}/{{ .rsskey }}/{{ .torrentName }}.torrent" torrenturl: "/rss/download/{{ .torrentId }}/{{ .rsskey }}/{{ .torrentName }}.torrent"
encode: encode:
- torrentName - torrentName

View file

@ -79,13 +79,13 @@ irc:
label: Invite command label: Invite command
help: Invite auth with Drone. Replace USERNAME and IRCKEY. help: Invite auth with Drone. Replace USERNAME and IRCKEY.
parse: parse:
type: single type: single
lines: lines:
- test: - test:
- "Artist - Albumname [2008] [Single] - FLAC / Lossless / Log / 100% / Cue / CD - https://redacted.ch/torrents.php?id=0000000 / https://redacted.ch/torrents.php?action=download&id=0000000 - hip.hop,rhythm.and.blues,2000s" - "Artist - Albumname [2008] [Single] - FLAC / Lossless / Log / 100% / Cue / CD - https://redacted.ch/torrents.php?id=0000000 / https://redacted.ch/torrents.php?action=download&id=0000000 - hip.hop,rhythm.and.blues,2000s"
- "A really long name here - Concertos 5 and 6, Suite No 2 [1991] [Album] - FLAC / Lossless / Log / 100% / Cue / CD - https://redacted.ch/torrents.php?id=0000000 / https://redacted.ch/torrents.php?action=download&id=0000000 - classical" - "A really long name here - Concertos 5 and 6, Suite No 2 [1991] [Album] - FLAC / Lossless / Log / 100% / Cue / CD - https://redacted.ch/torrents.php?id=0000000 / https://redacted.ch/torrents.php?action=download&id=0000000 - classical"
pattern: '(.*) (?:\[(.*)\] \[(.*)\] - (.*))? .* \/ (https?\:\/\/.*id=(\d+))\s* -\s*(.*)' pattern: '(.*) (?:\[(.*)\] \[(.*)\] - (.*))? .* \/ (https?\:\/\/.+\/).+id=(\d+) - (.+)'
vars: vars:
- torrentName - torrentName
- year - year
@ -96,4 +96,4 @@ parse:
- tags - tags
match: match:
torrenturl: "{{ .baseUrl }}&authkey={{ .authkey }}&torrent_pass={{ .torrent_pass }}" torrenturl: "/torrents.php?action=download&id={{ .torrentId }}&authkey={{ .authkey }}&torrent_pass={{ .torrent_pass }}"

View file

@ -5,7 +5,7 @@ identifier: retroflix
description: RetroFlix (RFX) is a private torrent tracker for CLASSIC MOVIES / TV / GENERAL description: RetroFlix (RFX) is a private torrent tracker for CLASSIC MOVIES / TV / GENERAL
language: en-us language: en-us
urls: urls:
- https://retroflix.club - https://retroflix.club/
privacy: private privacy: private
protocol: torrent protocol: torrent
supports: supports:
@ -50,7 +50,7 @@ irc:
label: NickServ Password label: NickServ Password
help: NickServ password help: NickServ password
parse: parse:
type: single type: single
lines: lines:
- test: - test:
@ -65,6 +65,6 @@ parse:
- torrentId - torrentId
match: match:
torrenturl: "{{ .baseUrl }}download.php?id={{ .torrentId }}&passkey={{ .passkey }}" torrenturl: "/download.php?id={{ .torrentId }}&passkey={{ .passkey }}"
encode: encode:
- torrentName - torrentName

View file

@ -5,7 +5,7 @@ identifier: revolutiontt
description: RevolutionTT (RTT) is a private torrent tracker for 0DAY / GENERAL. description: RevolutionTT (RTT) is a private torrent tracker for 0DAY / GENERAL.
language: en-us language: en-us
urls: urls:
- https://www.revolutiontt.me - https://www.revolutiontt.me/
privacy: private privacy: private
protocol: torrent protocol: torrent
supports: supports:
@ -54,7 +54,7 @@ irc:
label: Invite command label: Invite command
help: Invite auth with RevoTT. Replace USERNAME and PASSKEY help: Invite auth with RevoTT. Replace USERNAME and PASSKEY
parse: parse:
type: single type: single
lines: lines:
- test: - test:
@ -68,8 +68,6 @@ parse:
- torrentId - torrentId
match: match:
torrenturl: "{{ .baseUrl }}download.php/{{ .torrentId }}/{{ .torrentName }}.torrent?passkey={{ .passkey }}" torrenturl: "/download.php/{{ .torrentId }}/{{ .torrentName }}.torrent?passkey={{ .passkey }}"
encode: encode:
- torrentName - torrentName

View file

@ -5,7 +5,7 @@ identifier: scenehd
description: SceneHD (SCHD) is a private torrent tracker for HD MOVIES / TV. description: SceneHD (SCHD) is a private torrent tracker for HD MOVIES / TV.
language: en-us language: en-us
urls: urls:
- https://scenehd.org - https://scenehd.org/
privacy: private privacy: private
protocol: torrent protocol: torrent
supports: supports:
@ -54,12 +54,12 @@ irc:
label: Invite command label: Invite command
help: Invite auth with SceneHD. Replace IRCKEY with your IRC key help: Invite auth with SceneHD. Replace IRCKEY with your IRC key
parse: parse:
type: single type: single
lines: lines:
- test: - test:
- "[NEW] Some.Show.S08E20.EXTENDED.720p.BluRay.X264-GROUP [TV/720] https://scenehd.org/details.php?id=00000" - "[NEW] Some.Show.S08E20.EXTENDED.720p.BluRay.X264-GROUP [TV/720] https://scenehd.org/details.php?id=00000"
pattern: '\[NEW] (.*) \[([^\]]+)] (https?\:\/\/[^\/]+)\/.*[&\?]id=(\d+)' pattern: '\[NEW] (.+) \[(.+)] (https?\:\/\/.+\/).*id=(\d+)'
vars: vars:
- torrentName - torrentName
- category - category
@ -67,4 +67,4 @@ parse:
- torrentId - torrentId
match: match:
torrenturl: "{{ .baseUrl }}/download.php?id={{ .torrentId }}&passkey={{ .passkey }}" torrenturl: "/download.php?id={{ .torrentId }}&passkey={{ .passkey }}"

View file

@ -46,13 +46,13 @@ irc:
label: NickServ Password label: NickServ Password
help: NickServ password help: NickServ password
parse: parse:
type: single type: single
lines: lines:
- test: - test:
- "New! (Movies HD-RO) - Some.File.2022.1080p.WEB-DL.DDP5.1.Atmos.H.264.mkv - (5.14 GB) - https://speedapp.io/browse/00000/t/some-file-2022-1080p-web-dl-ddp5-1-atmos-h-264-mkv" - "New! (Movies HD-RO) - Some.File.2022.1080p.WEB-DL.DDP5.1.Atmos.H.264.mkv - (5.14 GB) - https://speedapp.io/browse/00000/t/some-file-2022-1080p-web-dl-ddp5-1-atmos-h-264-mkv"
- "New! (XXX HD) - Some.XXX.21.05.19.famous.actress.XXX.1080p.MP4-WRB - (841.64 MB) - https://speedapp.io/browse/000000/t/some-xxx-21-05-19-famous-actress-xxx-1080p-mp4-wrb" - "New! (XXX HD) - Some.XXX.21.05.19.famous.actress.XXX.1080p.MP4-WRB - (841.64 MB) - https://speedapp.io/browse/000000/t/some-xxx-21-05-19-famous-actress-xxx-1080p-mp4-wrb"
pattern: 'New! \((.*)\) - (.*) - \((.*)\) - (https?:\/\/.*)\/browse/(\d+)/t/(.*)' pattern: 'New! \((.+)\) - (.+) - \((.+)\) - (https?:\/\/.+\/)browse\/(\d+)\/t\/(.+)'
vars: vars:
- category - category
- torrentName - torrentName
@ -61,4 +61,4 @@ parse:
- torrentId - torrentId
match: match:
torrenturl: "{{ .baseUrl }}/rss/download/{{ .torrentId }}/{{ .torrentName }}.torrent?passkey={{ .passkey }}" torrenturl: "/rss/download/{{ .torrentId }}/{{ .torrentName }}.torrent?passkey={{ .passkey }}"

View file

@ -5,7 +5,7 @@ identifier: subsplease
description: SubsPlease is an indexer for Anime. description: SubsPlease is an indexer for Anime.
language: en-us language: en-us
urls: urls:
- https://subsplease.org - https://subsplease.org/
privacy: public privacy: public
protocol: torrent protocol: torrent
supports: supports:
@ -41,7 +41,7 @@ irc:
label: NickServ Password label: NickServ Password
help: NickServ password help: NickServ password
parse: parse:
type: single type: single
lines: lines:
- pattern: '\[Release\] (.*(SubsPlease).*.(mkv)) \((.*)\) - .* - (.*)' - pattern: '\[Release\] (.*(SubsPlease).*.(mkv)) \((.*)\) - .* - (.*)'
@ -53,4 +53,4 @@ parse:
- torrentUrl - torrentUrl
match: match:
torrenturl: "{{.torrentUrl}}" torrenturl: "{{ .torrentUrl }}"

View file

@ -47,7 +47,7 @@ irc:
label: NickServ Password label: NickServ Password
help: NickServ password help: NickServ password
parse: parse:
type: single type: single
lines: lines:
- test: - test:
@ -64,4 +64,4 @@ parse:
- preTime - preTime
match: match:
torrenturl: "https://superbits.org/download.php?id={{ .torrentId }}&passkey={{ .passkey }}" torrenturl: "/download.php?id={{ .torrentId }}&passkey={{ .passkey }}"

View file

@ -54,7 +54,7 @@ irc:
label: Invite command label: Invite command
help: Invite auth with Erica, please replace USERNAME and IRCKEY. help: Invite auth with Erica, please replace USERNAME and IRCKEY.
parse: parse:
type: single type: single
lines: lines:
- test: - test:
@ -67,7 +67,7 @@ parse:
- preTime - preTime
match: match:
torrenturl: "{{ .baseUrl }}download.php?id={{ .torrentId }}&SSL=1&name={{ .torrentName }}.torrent" torrenturl: "/download.php?id={{ .torrentId }}&SSL=1&name={{ .torrentName }}.torrent"
cookie: true cookie: true
encode: encode:
- torrentName - torrentName

View file

@ -5,7 +5,15 @@ identifier: torrentday
description: TorrentDay (TD) is a private torrent tracker for GENERAL. description: TorrentDay (TD) is a private torrent tracker for GENERAL.
language: en-us language: en-us
urls: urls:
- https://www.torrentday.com - https://www.torrentday.com/
- https://tday.love/
- https://secure.torrentday.com/
- https://classic.torrentday.com/
- https://torrentday.it/
- https://td.findnemo.net/
- https://td.getcrazy.me/
- https://td.venom.global/
- https://td.workisboring.net/
privacy: private privacy: private
protocol: torrent protocol: torrent
supports: supports:
@ -47,13 +55,13 @@ irc:
label: NickServ Password label: NickServ Password
help: NickServ password help: NickServ password
parse: parse:
type: single type: single
lines: lines:
- test: - test:
- "[Movie/4K] This is a Movie 2160p UHD BluRay x265-TEST - https://www.torrentday.com/details.php?id=0000000 - 5.83 GB" - "[Movie/4K] This is a Movie 2160p UHD BluRay x265-TEST - https://www.torrentday.com/details.php?id=0000000 - 5.83 GB"
- "[Movie/4K] This is a Movie 2160p UHD BluRay x265-TEST FREELEECH - https://www.torrentday.com/details.php?id=0000000 - 5.83 GB" - "[Movie/4K] This is a Movie 2160p UHD BluRay x265-TEST FREELEECH - https://www.torrentday.com/details.php?id=0000000 - 5.83 GB"
pattern: '\[([^\]]*)] (.*?)\s*(FREELEECH)*\s*-\s+(https?\:\/\/[^\/]+).*[&\?]id=(\d+)\s*- (.*)' pattern: '\[([^\]]*)] (.*?)\s*(FREELEECH)*\s*-\s+(https?\:\/\/[^\/]+\/).*[&\?]id=(\d+)\s*- (.*)'
vars: vars:
- category - category
- torrentName - torrentName
@ -63,6 +71,6 @@ parse:
- torrentSize - torrentSize
match: match:
torrenturl: "{{ .baseUrl }}/download.php/{{ .torrentId }}/{{ .torrentName }}.torrent?torrent_pass={{ .passkey }}" torrenturl: "/download.php/{{ .torrentId }}/{{ .torrentName }}.torrent?torrent_pass={{ .passkey }}"
encode: encode:
- torrentName - torrentName

View file

@ -47,7 +47,7 @@ irc:
label: NickServ Password label: NickServ Password
help: NickServ password help: NickServ password
parse: parse:
type: single type: single
lines: lines:
- test: - test:
@ -64,4 +64,4 @@ parse:
- torrentId - torrentId
match: match:
torrenturl: "{{ .baseUrl }}torrent/download/irssi/{{ .torrentId }}/{{ .passkey }}" torrenturl: "/torrent/download/irssi/{{ .torrentId }}/{{ .passkey }}"

View file

@ -5,7 +5,11 @@ identifier: torrentleech
description: TorrentLeech (TL) is a private torrent tracker for 0DAY / GENERAL. description: TorrentLeech (TL) is a private torrent tracker for 0DAY / GENERAL.
language: en-us language: en-us
urls: urls:
- https://www.torrentleech.org - https://www.torrentleech.org/
- https://www.torrentleech.cc/
- https://www.torrentleech.me/
- https://www.tleechreload.org/
- https://www.tlgetin.cc/
privacy: private privacy: private
protocol: torrent protocol: torrent
supports: supports:
@ -48,7 +52,7 @@ irc:
label: NickServ Password label: NickServ Password
help: NickServ password help: NickServ password
parse: parse:
type: single type: single
lines: lines:
- test: - test:
@ -64,8 +68,6 @@ parse:
- torrentId - torrentId
match: match:
torrenturl: "{{ .baseUrl }}rss/download/{{ .torrentId }}/{{ .rsskey }}/{{ .torrentName }}.torrent" torrenturl: "/rss/download/{{ .torrentId }}/{{ .rsskey }}/{{ .torrentName }}.torrent"
encode: encode:
- torrentName - torrentName

View file

@ -47,7 +47,7 @@ irc:
label: NickServ Password label: NickServ Password
help: NickServ password help: NickServ password
parse: parse:
type: multi type: multi
lines: lines:
- test: - test:
@ -59,11 +59,11 @@ parse:
- preTime - preTime
- test: - test:
- "{New Torrent} Size {24.629 MiB} Files {5} Link {https://tntracker.org/torrent/000000}" - "{New Torrent} Size {24.629 MiB} Files {5} Link {https://tntracker.org/torrent/000000}"
pattern: '\{New Torrent\} Size \{(.*)\} Files \{\d+\} Link \{(https?:\/\/[^\/]+)\/torrent\/(\d+)\}' pattern: '\{New Torrent\} Size \{(.*)\} Files \{\d+\} Link \{(https?:\/\/[^\/]+\/)torrent\/(\d+)\}'
vars: vars:
- torrentSize - torrentSize
- baseUrl - baseUrl
- torrentId - torrentId
match: match:
torrenturl: "{{ .baseUrl }}/download/{{ .torrentId }}/{{ .passkey }}" torrenturl: "/download/{{ .torrentId }}/{{ .passkey }}"

View file

@ -5,7 +5,7 @@ identifier: torrentseeds
description: TorrentSeeds (TS) is a GENERAL/0-DAY tracker with great pretimes. description: TorrentSeeds (TS) is a GENERAL/0-DAY tracker with great pretimes.
language: en-us language: en-us
urls: urls:
- https://torrentseeds.org - https://torrentseeds.org/
privacy: private privacy: private
protocol: torrent protocol: torrent
supports: supports:
@ -54,12 +54,12 @@ irc:
label: Invite command label: Invite command
help: Invite auth with Cerberus. Replace USERNAME and PID (passkey). help: Invite auth with Cerberus. Replace USERNAME and PID (passkey).
parse: parse:
type: single type: single
lines: lines:
- test: - test:
- "New: This.Is.A.New.show.S00E00.720p.WEB.H264-Test .:. Category: TV/HD .:. Size: 364.82 MB .:. URL: https://www.torrentseeds.org/details.php?id=000000 .:. Uploaded by: George." - "New: This.Is.A.New.show.S00E00.720p.WEB.H264-Test .:. Category: TV/HD .:. Size: 364.82 MB .:. URL: https://www.torrentseeds.org/details.php?id=000000 .:. Uploaded by: George."
pattern: 'New: (.*) \.:\. Category: (.*) \.:\. Size: (.*) \.:\. URL: (https?\:\/\/[^\/]+).*\/(\d{6,9}) \.:\. Uploaded by: (.*)\.' pattern: 'New: (.+) \.:\. Category: (.+) \.:\. Size: (.+) \.:\. URL: (https?\:\/\/.+\/).+id=(\d+) \.:\. Uploaded by: (.*)\.'
vars: vars:
- torrentName - torrentName
- category - category
@ -69,4 +69,4 @@ parse:
- uploader - uploader
match: match:
torrenturl: "{{ .baseUrl }}/torrent/download/{{ .torrentId }}.{{ .rsskey }}" torrenturl: "/torrent/download/{{ .torrentId }}.{{ .rsskey }}"

View file

@ -54,14 +54,14 @@ irc:
label: Invite command label: Invite command
help: Invite auth with Synd1c4t3. Replace IRCKEY help: Invite auth with Synd1c4t3. Replace IRCKEY
parse: parse:
type: single type: single
lines: lines:
- test: - test:
- "NEU Welcome.to.the.N.H.K.S01E15.German.DL.AC3.720p.BluRay.x264-ABJ [Serien/720p] [P2P] [678.68 MB] -- https://torrent-syndikat.org/details.php?id=000000 | Animation, Anime, Comedy, Drama, Romance, Thriller, Encode, AVC, DL, PID:00000, tt0857297" - "NEU Welcome.to.the.N.H.K.S01E15.German.DL.AC3.720p.BluRay.x264-ABJ [Serien/720p] [P2P] [678.68 MB] -- https://torrent-syndikat.org/details.php?id=000000 | Animation, Anime, Comedy, Drama, Romance, Thriller, Encode, AVC, DL, PID:00000, tt0857297"
- "NEU KLIM_Beats-FireFlies-WEB-2016-KNOWN [Audio/Musik/MP3] [O-SCENE] [59.82 MB] -- https://torrent-syndikat.org/details.php?id=000000 | Hip-Hop" - "NEU KLIM_Beats-FireFlies-WEB-2016-KNOWN [Audio/Musik/MP3] [O-SCENE] [59.82 MB] -- https://torrent-syndikat.org/details.php?id=000000 | Hip-Hop"
- "NEU DarkSpar-DARKZER0 [Spiele/Windows] [O-SCENE] [54.46 MB] -- https://torrent-syndikat.org/details.php?id=000000 | " - "NEU DarkSpar-DARKZER0 [Spiele/Windows] [O-SCENE] [54.46 MB] -- https://torrent-syndikat.org/details.php?id=000000 | "
pattern: '^NEU (.*) \[(.*)\] \[(.*)\] \[(.*)\] -- (https?\:\/\/[^\/]+)\/.*\?id=(\d+) \| (.*)' pattern: 'NEU (.+) \[(.+)\] \[(.+)\] \[(.+)\] -- (https?\:\/\/.+\/).+id=(\d+) \| (.+)'
vars: vars:
- torrentName - torrentName
- category - category
@ -71,4 +71,4 @@ parse:
- torrentId - torrentId
- tags - tags
match: match:
torrenturl: "{{ .baseUrl }}/download.php?id={{ .torrentId }}&apikey={{ .api_key }}" torrenturl: "/download.php?id={{ .torrentId }}&apikey={{ .api_key }}"

View file

@ -47,7 +47,7 @@ irc:
label: NickServ Password label: NickServ Password
help: NickServ password help: NickServ password
parse: parse:
type: multi type: multi
lines: lines:
- test: - test:
@ -76,6 +76,6 @@ parse:
- torrentId - torrentId
match: match:
torrenturl: "{{ .baseUrl }}download.php/{{ .torrentId }}/{{ .torrentName }}.torrent?passkey={{ .passkey }}" torrenturl: "/download.php/{{ .torrentId }}/{{ .torrentName }}.torrent?passkey={{ .passkey }}"
encode: encode:
- torrentName - torrentName

View file

@ -61,12 +61,12 @@ irc:
label: Invite command label: Invite command
help: Invite auth with UHDBot. Replace IRCKEY. help: Invite auth with UHDBot. Replace IRCKEY.
parse: parse:
type: single type: single
lines: lines:
- test: - test:
- "New Torrent: A Movie [2015] - GROUP Type: Movie / 1080p / Encode / Freeleech: 100 Size: 7.00GB - https://uhdbits.org/torrents.php?id=00000 / https://uhdbits.org/torrents.php?action=download&id=00000" - "New Torrent: A Movie [2015] - GROUP Type: Movie / 1080p / Encode / Freeleech: 100 Size: 7.00GB - https://uhdbits.org/torrents.php?id=00000 / https://uhdbits.org/torrents.php?action=download&id=00000"
pattern: 'New Torrent: (.*) Type: (.*?) \/ (.*?) Freeleech: (.*) Size: (.*) - https?:\/\/.* \/ (https?:\/\/.*id=\d+)' pattern: 'New Torrent: (.+) Type: (.+?) \/ (.*?) Freeleech: (.+) Size: (.+) - https?:\/\/.+ \/ (https?:\/\/.+\/).+id=(\d+)'
vars: vars:
- torrentName - torrentName
- category - category
@ -74,6 +74,7 @@ parse:
- freeleechPercent - freeleechPercent
- torrentSize - torrentSize
- baseUrl - baseUrl
- torrentId
match: match:
torrenturl: "{{ .baseUrl }}&authkey={{ .authkey }}&torrent_pass={{ .torrent_pass }}" torrenturl: "/torrents.php?action=download&id={{ .torrentId }}&authkey={{ .authkey }}&torrent_pass={{ .torrent_pass }}"

View file

@ -5,7 +5,7 @@ identifier: xspeeds
description: XSpeeds (XS) is a private torrent tracker for MOVIES / TV / GENERAL. description: XSpeeds (XS) is a private torrent tracker for MOVIES / TV / GENERAL.
language: en-us language: en-us
urls: urls:
- https://xspeeds.eu - https://xspeeds.eu/
privacy: private privacy: private
protocol: torrent protocol: torrent
supports: supports:
@ -47,7 +47,7 @@ irc:
label: NickServ Password label: NickServ Password
help: NickServ password help: NickServ password
categories: categories:
- 4K Movies - 4K Movies
- 4K TV - 4K TV
- 4K TV Boxsets - 4K TV Boxsets
@ -87,14 +87,14 @@ categories:
- Wrestling - Wrestling
- Xbox Games - Xbox Games
parse: parse:
type: single type: single
lines: lines:
- test: - test:
- "xspeeds.eu - New Torrent: ( The.Best.Show.S03E07.720p.BluRay.x264-GROUP ) Size: ( 1.96 GB ) Category: ( TV-HD ) Uploader: ( uploader1 ) Link: ( https://www.xspeeds.eu/details.php?id=0000000 )" - "xspeeds.eu - New Torrent: ( The.Best.Show.S03E07.720p.BluRay.x264-GROUP ) Size: ( 1.96 GB ) Category: ( TV-HD ) Uploader: ( uploader1 ) Link: ( https://www.xspeeds.eu/details.php?id=0000000 )"
- "xspeeds.eu - New Torrent: ( Some.Show.S21E06.1080p.HEVC.x265-GROUP1 ) Size: ( 1.04 GB ) Category: ( HEVC ) Uploader: ( uploader2 ) Link: ( https://www.xspeeds.eu/details.php?id=0000000 )" - "xspeeds.eu - New Torrent: ( Some.Show.S21E06.1080p.HEVC.x265-GROUP1 ) Size: ( 1.04 GB ) Category: ( HEVC ) Uploader: ( uploader2 ) Link: ( https://www.xspeeds.eu/details.php?id=0000000 )"
- "xspeeds.eu - New Torrent: ( Some.Show.S21E06.XviD-GROUP2 ) Size: ( 861.32 MB ) Category: ( TV-SD ) Uploader: ( uploader2 ) Link: ( https://www.xspeeds.eu/details.php?id=0000000 )" - "xspeeds.eu - New Torrent: ( Some.Show.S21E06.XviD-GROUP2 ) Size: ( 861.32 MB ) Category: ( TV-SD ) Uploader: ( uploader2 ) Link: ( https://www.xspeeds.eu/details.php?id=0000000 )"
pattern: '\s*xspeeds.eu - New Torrent: \( (.*) \) Size: \( ([^)]*) \)\s*Category: \( ([^)]*) \) Uploader: \( ([^)]*) \) Link: \( (https?\:\/\/[^\/]+)\/.*[&\?]id=(\d+) \)' pattern: '\s*xspeeds.eu - New Torrent: \( (.*) \) Size: \( ([^)]*) \)\s*Category: \( ([^)]*) \) Uploader: \( ([^)]*) \) Link: \( (https?\:\/\/[^\/]+\/).*[&\?]id=(\d+) \)'
vars: vars:
- torrentName - torrentName
- torrentSize - torrentSize
@ -104,4 +104,4 @@ parse:
- torrentId - torrentId
match: match:
torrenturl: "{{ .baseUrl }}/download.php?type=rss&secret_key={{ .passkey }}&id={{ .torrentId }}" torrenturl: "/download.php?type=rss&secret_key={{ .passkey }}&id={{ .torrentId }}"

View file

@ -227,6 +227,7 @@ func (s *service) mapIndexer(indexer domain.Indexer) (*domain.IndexerDefinition,
d.Name = indexer.Name d.Name = indexer.Name
d.Identifier = indexer.Identifier d.Identifier = indexer.Identifier
d.Implementation = indexer.Implementation d.Implementation = indexer.Implementation
d.BaseURL = indexer.BaseURL
d.Enabled = indexer.Enabled d.Enabled = indexer.Enabled
if d.SettingsMap == nil { if d.SettingsMap == nil {
@ -262,6 +263,7 @@ func (s *service) updateMapIndexer(indexer domain.Indexer) (*domain.IndexerDefin
d.Name = indexer.Name d.Name = indexer.Name
d.Identifier = indexer.Identifier d.Identifier = indexer.Identifier
d.Implementation = indexer.Implementation d.Implementation = indexer.Implementation
d.BaseURL = indexer.BaseURL
d.Enabled = indexer.Enabled d.Enabled = indexer.Enabled
if d.SettingsMap == nil { if d.SettingsMap == nil {
@ -300,16 +302,14 @@ func (s *service) GetTemplates() ([]domain.IndexerDefinition, error) {
func (s *service) Start() error { func (s *service) Start() error {
// load all indexer definitions // load all indexer definitions
err := s.LoadIndexerDefinitions() if err := s.LoadIndexerDefinitions(); err != nil {
if err != nil {
s.log.Error().Err(err).Msg("could not load indexer definitions") s.log.Error().Err(err).Msg("could not load indexer definitions")
return err return err
} }
if s.config.CustomDefinitions != "" { if s.config.CustomDefinitions != "" {
// load custom indexer definitions // load custom indexer definitions
err = s.LoadCustomIndexerDefinitions() if err := s.LoadCustomIndexerDefinitions(); err != nil {
if err != nil {
return errors.Wrap(err, "could not load custom indexer definitions") return errors.Wrap(err, "could not load custom indexer definitions")
} }
} }
@ -356,8 +356,6 @@ func (s *service) removeIndexer(indexer domain.Indexer) {
// remove mapped definition // remove mapped definition
delete(s.mappedDefinitions, indexer.Identifier) delete(s.mappedDefinitions, indexer.Identifier)
return
} }
func (s *service) addIndexer(indexer domain.Indexer) error { func (s *service) addIndexer(indexer domain.Indexer) error {
@ -465,16 +463,14 @@ func (s *service) LoadIndexerDefinitions() error {
s.log.Trace().Msgf("parsing: %v", file) s.log.Trace().Msgf("parsing: %v", file)
var d *domain.IndexerDefinition
data, err := fs.ReadFile(Definitions, file) data, err := fs.ReadFile(Definitions, file)
if err != nil { if err != nil {
s.log.Error().Stack().Err(err).Msgf("failed reading file: %v", file) s.log.Error().Stack().Err(err).Msgf("failed reading file: %v", file)
return errors.Wrap(err, "could not read file: %v", file) return errors.Wrap(err, "could not read file: %v", file)
} }
err = yaml.Unmarshal(data, &d) var d domain.IndexerDefinition
if err != nil { if err = yaml.Unmarshal(data, &d); err != nil {
s.log.Error().Stack().Err(err).Msgf("failed unmarshal file: %v", file) s.log.Error().Stack().Err(err).Msgf("failed unmarshal file: %v", file)
return errors.Wrap(err, "could not unmarshal file: %v", file) return errors.Wrap(err, "could not unmarshal file: %v", file)
} }
@ -483,7 +479,7 @@ func (s *service) LoadIndexerDefinitions() error {
d.Implementation = "irc" d.Implementation = "irc"
} }
s.definitions[d.Identifier] = *d s.definitions[d.Identifier] = d
} }
s.log.Debug().Msgf("Loaded %d indexer definitions", len(s.definitions)) s.log.Debug().Msgf("Loaded %d indexer definitions", len(s.definitions))
@ -524,14 +520,13 @@ func (s *service) LoadCustomIndexerDefinitions() error {
s.log.Trace().Msgf("parsing custom: %v", file) s.log.Trace().Msgf("parsing custom: %v", file)
//data, err := fs.ReadFile(Definitions, filePath)
data, err := os.ReadFile(file) data, err := os.ReadFile(file)
if err != nil { if err != nil {
s.log.Error().Stack().Err(err).Msgf("failed reading file: %v", file) s.log.Error().Stack().Err(err).Msgf("failed reading file: %v", file)
return errors.Wrap(err, "could not read file: %v", file) return errors.Wrap(err, "could not read file: %v", file)
} }
var d *domain.IndexerDefinition var d *domain.IndexerDefinitionCustom
if err = yaml.Unmarshal(data, &d); err != nil { if err = yaml.Unmarshal(data, &d); err != nil {
s.log.Error().Stack().Err(err).Msgf("failed unmarshal file: %v", file) s.log.Error().Stack().Err(err).Msgf("failed unmarshal file: %v", file)
return errors.Wrap(err, "could not unmarshal file: %v", file) return errors.Wrap(err, "could not unmarshal file: %v", file)
@ -546,7 +541,12 @@ func (s *service) LoadCustomIndexerDefinitions() error {
d.Implementation = "irc" d.Implementation = "irc"
} }
s.definitions[d.Identifier] = *d // to prevent crashing from non-updated definitions lets skip
if d.Implementation == "irc" && d.IRC.Parse == nil {
s.log.Warn().Msgf("DEPRECATED: indexer definition version: %v", file)
}
s.definitions[d.Identifier] = *d.ToIndexerDefinition()
customCount++ customCount++
} }

View file

@ -5,7 +5,7 @@ identifier: mock
description: MockIndexer is a mock indexer. description: MockIndexer is a mock indexer.
language: en-us language: en-us
urls: urls:
- http://localhost.test - http://localhost.test/
privacy: private privacy: private
protocol: torrent protocol: torrent
supports: supports:
@ -47,7 +47,7 @@ irc:
label: NickServ Password label: NickServ Password
help: NickServ password help: NickServ password
parse: parse:
type: single type: single
lines: lines:
- test: - test:
@ -63,8 +63,6 @@ parse:
- torrentId - torrentId
match: match:
torrenturl: "{{ .baseUrl }}rss/download/{{ .torrentId }}/{{ .rsskey }}/{{ .torrentName }}.torrent" torrenturl: "/rss/download/{{ .torrentId }}/{{ .rsskey }}/{{ .torrentName }}.torrent"
encode: encode:
- torrentName - torrentName

View file

@ -0,0 +1,119 @@
import type { FieldProps } from "formik";
import { Field } from "formik";
import { components, ControlProps, InputProps, MenuProps, OptionProps } from "react-select";
import { OptionBasicTyped } from "../../domain/constants";
import CreatableSelect from "react-select/creatable";
interface SelectFieldProps<T> {
name: string;
label: string;
help?: string;
placeholder?: string;
options: OptionBasicTyped<T>[]
}
export function SelectFieldCreatable<T>({ name, label, help, placeholder, options }: SelectFieldProps<T>) {
return (
<div className="space-y-1 p-4 sm:space-y-0 sm:grid sm:grid-cols-3 sm:gap-4">
<div>
<label
htmlFor={name}
className="block text-sm font-medium text-gray-900 dark:text-white sm:pt-2"
>
{label}
</label>
</div>
<div className="sm:col-span-2">
<Field name={name} type="select">
{({
field,
form: { setFieldValue }
}: FieldProps) => (
<CreatableSelect
{...field}
id={name}
isClearable={true}
isSearchable={true}
components={{
Input,
Control,
Menu,
Option
}}
placeholder={placeholder ?? "Choose an option"}
styles={{
singleValue: (base) => ({
...base,
color: "unset"
})
}}
theme={(theme) => ({
...theme,
spacing: {
...theme.spacing,
controlHeight: 30,
baseUnit: 2
}
})}
// value={field?.value ? field.value : options.find(o => o.value == field?.value)}
value={field?.value ? { value: field.value, label: field.value } : field.value}
onChange={(option) => {
if (option === null) {
setFieldValue(field.name, "");
return;
} else {
setFieldValue(field.name, option.value ?? "");
}
}}
options={[...[...options, { value: field.value, label: field.value }].reduce((map, obj) => map.set(obj.value, obj), new Map()).values()]}
/>
)}
</Field>
{help && (
<p className="mt-2 text-sm text-gray-500" id={`${name}-description`}>{help}</p>
)}
</div>
</div>
);
}
const Input = (props: InputProps) => {
return (
<components.Input
{...props}
inputClassName="outline-none border-none shadow-none focus:ring-transparent"
className="text-gray-400 dark:text-gray-100"
children={props.children}
/>
);
};
const Control = (props: ControlProps) => {
return (
<components.Control
{...props}
className="p-1 block w-full dark:bg-gray-800 border border-gray-300 dark:border-gray-700 rounded-md shadow-sm focus:outline-none focus:ring-blue-500 focus:border-blue-500 dark:text-gray-100 sm:text-sm"
children={props.children}
/>
);
};
const Menu = (props: MenuProps) => {
return (
<components.Menu
{...props}
className="dark:bg-gray-800 border border-gray-300 dark:border-gray-700 dark:text-gray-400 rounded-md shadow-sm"
children={props.children}
/>
);
};
const Option = (props: OptionProps) => {
return (
<components.Option
{...props}
className="dark:text-gray-400 dark:bg-gray-800 dark:hover:bg-gray-900 dark:focus:bg-gray-900"
children={props.children}
/>
);
};

View file

@ -15,6 +15,7 @@ import { APIClient } from "../../api/APIClient";
import { PasswordFieldWide, SwitchGroupWide, TextFieldWide } from "../../components/inputs"; import { PasswordFieldWide, SwitchGroupWide, TextFieldWide } from "../../components/inputs";
import { SlideOver } from "../../components/panels"; import { SlideOver } from "../../components/panels";
import Toast from "../../components/notifications/Toast"; import Toast from "../../components/notifications/Toast";
import { SelectFieldCreatable } from "../../components/inputs/select_wide";
const Input = (props: InputProps) => ( const Input = (props: InputProps) => (
<components.Input <components.Input
@ -423,6 +424,7 @@ export function IndexerAddForm({ isOpen, toggle }: AddProps) {
setFieldValue("implementation", ind.implementation); setFieldValue("implementation", ind.implementation);
if (ind.irc && ind.irc.settings) { if (ind.irc && ind.irc.settings) {
setFieldValue("base_url", ind.urls[0]);
ind.irc.settings.forEach((s) => { ind.irc.settings.forEach((s) => {
setFieldValue(`irc.${s.name}`, s.default ?? ""); setFieldValue(`irc.${s.name}`, s.default ?? "");
}); });
@ -443,6 +445,15 @@ export function IndexerAddForm({ isOpen, toggle }: AddProps) {
<SwitchGroupWide name="enabled" label="Enabled" /> <SwitchGroupWide name="enabled" label="Enabled" />
{indexer.implementation == "irc" && (
<SelectFieldCreatable
name="base_url"
label="Base URL"
help="Override baseurl if it's blocked by your ISP."
options={indexer.urls.map(u => ({ value: u, label: u, key: u })) }
/>
)}
{SettingFields(indexer, values.identifier)} {SettingFields(indexer, values.identifier)}
</div> </div>
@ -550,6 +561,7 @@ export function IndexerUpdateForm({ isOpen, toggle, indexer }: UpdateProps) {
enabled: indexer.enabled, enabled: indexer.enabled,
identifier: indexer.identifier, identifier: indexer.identifier,
implementation: indexer.implementation, implementation: indexer.implementation,
base_url: indexer.base_url,
settings: indexer.settings?.reduce( settings: indexer.settings?.reduce(
(o: Record<string, string>, obj: IndexerSetting) => ({ (o: Record<string, string>, obj: IndexerSetting) => ({
...o, ...o,
@ -592,6 +604,16 @@ export function IndexerUpdateForm({ isOpen, toggle, indexer }: UpdateProps) {
</Field> </Field>
</div> </div>
<SwitchGroupWide name="enabled" label="Enabled" /> <SwitchGroupWide name="enabled" label="Enabled" />
{indexer.implementation == "irc" && (
<SelectFieldCreatable
name="base_url"
label="Base URL"
help="Override baseurl if it's blocked by your ISP."
options={indexer.urls.map(u => ({ value: u, label: u, key: u })) }
/>
)}
{renderSettingFields(indexer.settings)} {renderSettingFields(indexer.settings)}
</div> </div>
)} )}

View file

@ -4,6 +4,7 @@ interface Indexer {
identifier: string; identifier: string;
enabled: boolean; enabled: boolean;
implementation: string; implementation: string;
base_url: string;
settings: Array<IndexerSetting>; settings: Array<IndexerSetting>;
} }
@ -12,6 +13,7 @@ interface IndexerDefinition {
name: string; name: string;
identifier: string; identifier: string;
implementation: string; implementation: string;
base_url: string;
enabled?: boolean; enabled?: boolean;
description: string; description: string;
language: string; language: string;