mirror of
https://github.com/idanoo/autobrr
synced 2025-07-23 00:39:13 +00:00
feat: add torznab feed support (#246)
* feat(torznab): initial impl * feat: torznab processing * feat: torznab more scheduling * feat: feeds web * feat(feeds): create on indexer create * feat(feeds): update migration * feat(feeds): restart on update * feat(feeds): set cron schedule * feat(feeds): use basic empty state * chore: remove duplicate migrations * feat: parse release size from torznab * chore: cleanup unused code
This commit is contained in:
parent
d4d864cd2c
commit
bb62e724a1
34 changed files with 2408 additions and 361 deletions
270
internal/database/feed.go
Normal file
270
internal/database/feed.go
Normal file
|
@ -0,0 +1,270 @@
|
|||
package database
|
||||
|
||||
import (
|
||||
"context"
|
||||
"database/sql"
|
||||
|
||||
"github.com/autobrr/autobrr/internal/domain"
|
||||
|
||||
sq "github.com/Masterminds/squirrel"
|
||||
"github.com/rs/zerolog/log"
|
||||
)
|
||||
|
||||
func NewFeedRepo(db *DB) domain.FeedRepo {
|
||||
return &FeedRepo{
|
||||
db: db,
|
||||
}
|
||||
}
|
||||
|
||||
type FeedRepo struct {
|
||||
db *DB
|
||||
}
|
||||
|
||||
func (r *FeedRepo) FindByID(ctx context.Context, id int) (*domain.Feed, error) {
|
||||
queryBuilder := r.db.squirrel.
|
||||
Select(
|
||||
"id",
|
||||
"indexer",
|
||||
"name",
|
||||
"type",
|
||||
"enabled",
|
||||
"url",
|
||||
"interval",
|
||||
"api_key",
|
||||
"created_at",
|
||||
"updated_at",
|
||||
).
|
||||
From("feed").
|
||||
Where("id = ?", id)
|
||||
|
||||
query, args, err := queryBuilder.ToSql()
|
||||
if err != nil {
|
||||
log.Error().Stack().Err(err).Msg("feed.FindById: error building query")
|
||||
return nil, err
|
||||
}
|
||||
|
||||
row := r.db.handler.QueryRowContext(ctx, query, args...)
|
||||
if err := row.Err(); err != nil {
|
||||
log.Error().Stack().Err(err).Msg("feed.FindById: error executing query")
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var f domain.Feed
|
||||
|
||||
var apiKey sql.NullString
|
||||
|
||||
if err := row.Scan(&f.ID, &f.Indexer, &f.Name, &f.Type, &f.Enabled, &f.URL, &f.Interval, &apiKey, &f.CreatedAt, &f.UpdatedAt); err != nil {
|
||||
log.Error().Stack().Err(err).Msg("feed.FindById: error scanning row")
|
||||
return nil, err
|
||||
|
||||
}
|
||||
|
||||
f.ApiKey = apiKey.String
|
||||
|
||||
return &f, nil
|
||||
}
|
||||
|
||||
func (r *FeedRepo) FindByIndexerIdentifier(ctx context.Context, indexer string) (*domain.Feed, error) {
|
||||
queryBuilder := r.db.squirrel.
|
||||
Select(
|
||||
"id",
|
||||
"indexer",
|
||||
"name",
|
||||
"type",
|
||||
"enabled",
|
||||
"url",
|
||||
"interval",
|
||||
"api_key",
|
||||
"created_at",
|
||||
"updated_at",
|
||||
).
|
||||
From("feed").
|
||||
Where("indexer = ?", indexer)
|
||||
|
||||
query, args, err := queryBuilder.ToSql()
|
||||
if err != nil {
|
||||
log.Error().Stack().Err(err).Msg("feed.FindByIndexerIdentifier: error building query")
|
||||
return nil, err
|
||||
}
|
||||
|
||||
row := r.db.handler.QueryRowContext(ctx, query, args...)
|
||||
if err := row.Err(); err != nil {
|
||||
log.Error().Stack().Err(err).Msg("feed.FindByIndexerIdentifier: error executing query")
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var f domain.Feed
|
||||
|
||||
var apiKey sql.NullString
|
||||
|
||||
if err := row.Scan(&f.ID, &f.Indexer, &f.Name, &f.Type, &f.Enabled, &f.URL, &f.Interval, &apiKey, &f.CreatedAt, &f.UpdatedAt); err != nil {
|
||||
log.Error().Stack().Err(err).Msg("feed.FindByIndexerIdentifier: error scanning row")
|
||||
return nil, err
|
||||
|
||||
}
|
||||
|
||||
f.ApiKey = apiKey.String
|
||||
|
||||
return &f, nil
|
||||
}
|
||||
|
||||
func (r *FeedRepo) Find(ctx context.Context) ([]domain.Feed, error) {
|
||||
queryBuilder := r.db.squirrel.
|
||||
Select(
|
||||
"id",
|
||||
"indexer",
|
||||
"name",
|
||||
"type",
|
||||
"enabled",
|
||||
"url",
|
||||
"interval",
|
||||
"api_key",
|
||||
"created_at",
|
||||
"updated_at",
|
||||
).
|
||||
From("feed").
|
||||
OrderBy("name ASC")
|
||||
|
||||
query, args, err := queryBuilder.ToSql()
|
||||
if err != nil {
|
||||
log.Error().Stack().Err(err).Msg("feed.Find: error building query")
|
||||
return nil, err
|
||||
}
|
||||
|
||||
rows, err := r.db.handler.QueryContext(ctx, query, args...)
|
||||
if err != nil {
|
||||
log.Error().Stack().Err(err).Msg("feed.Find: error executing query")
|
||||
return nil, err
|
||||
}
|
||||
|
||||
defer rows.Close()
|
||||
|
||||
feeds := make([]domain.Feed, 0)
|
||||
for rows.Next() {
|
||||
var f domain.Feed
|
||||
|
||||
var apiKey sql.NullString
|
||||
|
||||
if err := rows.Scan(&f.ID, &f.Indexer, &f.Name, &f.Type, &f.Enabled, &f.URL, &f.Interval, &apiKey, &f.CreatedAt, &f.UpdatedAt); err != nil {
|
||||
log.Error().Stack().Err(err).Msg("feed.Find: error scanning row")
|
||||
return nil, err
|
||||
|
||||
}
|
||||
|
||||
f.ApiKey = apiKey.String
|
||||
|
||||
feeds = append(feeds, f)
|
||||
}
|
||||
|
||||
return feeds, nil
|
||||
}
|
||||
|
||||
func (r *FeedRepo) Store(ctx context.Context, feed *domain.Feed) error {
|
||||
queryBuilder := r.db.squirrel.
|
||||
Insert("feed").
|
||||
Columns(
|
||||
"name",
|
||||
"indexer",
|
||||
"type",
|
||||
"enabled",
|
||||
"url",
|
||||
"interval",
|
||||
"api_key",
|
||||
"indexer_id",
|
||||
).
|
||||
Values(
|
||||
feed.Name,
|
||||
feed.Indexer,
|
||||
feed.Type,
|
||||
feed.Enabled,
|
||||
feed.URL,
|
||||
feed.Interval,
|
||||
feed.ApiKey,
|
||||
feed.IndexerID,
|
||||
).
|
||||
Suffix("RETURNING id").RunWith(r.db.handler)
|
||||
|
||||
var retID int
|
||||
|
||||
if err := queryBuilder.QueryRowContext(ctx).Scan(&retID); err != nil {
|
||||
log.Error().Stack().Err(err).Msg("feed.Store: error executing query")
|
||||
return err
|
||||
}
|
||||
|
||||
feed.ID = retID
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (r *FeedRepo) Update(ctx context.Context, feed *domain.Feed) error {
|
||||
queryBuilder := r.db.squirrel.
|
||||
Update("feed").
|
||||
Set("name", feed.Name).
|
||||
Set("indexer", feed.Indexer).
|
||||
Set("type", feed.Type).
|
||||
Set("enabled", feed.Enabled).
|
||||
Set("url", feed.URL).
|
||||
Set("interval", feed.Interval).
|
||||
Set("api_key", feed.ApiKey).
|
||||
Set("indexer_id", feed.IndexerID).
|
||||
Where("id = ?", feed.ID)
|
||||
|
||||
query, args, err := queryBuilder.ToSql()
|
||||
if err != nil {
|
||||
log.Error().Stack().Err(err).Msg("feed.Update: error building query")
|
||||
return err
|
||||
}
|
||||
|
||||
_, err = r.db.handler.ExecContext(ctx, query, args...)
|
||||
if err != nil {
|
||||
log.Error().Stack().Err(err).Msg("feed.Update: error executing query")
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (r *FeedRepo) ToggleEnabled(ctx context.Context, id int, enabled bool) error {
|
||||
var err error
|
||||
|
||||
queryBuilder := r.db.squirrel.
|
||||
Update("feed").
|
||||
Set("enabled", enabled).
|
||||
Set("updated_at", sq.Expr("CURRENT_TIMESTAMP")).
|
||||
Where("id = ?", id)
|
||||
|
||||
query, args, err := queryBuilder.ToSql()
|
||||
if err != nil {
|
||||
log.Error().Stack().Err(err).Msg("feed.ToggleEnabled: error building query")
|
||||
return err
|
||||
}
|
||||
_, err = r.db.handler.ExecContext(ctx, query, args...)
|
||||
if err != nil {
|
||||
log.Error().Stack().Err(err).Msg("feed.ToggleEnabled: error executing query")
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (r *FeedRepo) Delete(ctx context.Context, id int) error {
|
||||
queryBuilder := r.db.squirrel.
|
||||
Delete("feed").
|
||||
Where("id = ?", id)
|
||||
|
||||
query, args, err := queryBuilder.ToSql()
|
||||
if err != nil {
|
||||
log.Error().Stack().Err(err).Msg("feed.delete: error building query")
|
||||
return err
|
||||
}
|
||||
|
||||
_, err = r.db.handler.ExecContext(ctx, query, args...)
|
||||
if err != nil {
|
||||
log.Error().Stack().Err(err).Msg("feed.delete: error executing query")
|
||||
return err
|
||||
}
|
||||
|
||||
log.Info().Msgf("feed.delete: successfully deleted: %v", id)
|
||||
|
||||
return nil
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue