mirror of
https://github.com/idanoo/autobrr
synced 2025-07-23 08:49:13 +00:00
fix(feeds): indexer identifier issues (#538)
* fix(torznab/rss): keep original name * fix(feeds): get identifier via indexer join * fix(feeds/web): remove identifier slugify
This commit is contained in:
parent
dc42ca0042
commit
a93b54bbbc
4 changed files with 61 additions and 90 deletions
|
@ -27,22 +27,23 @@ type FeedRepo struct {
|
||||||
func (r *FeedRepo) FindByID(ctx context.Context, id int) (*domain.Feed, error) {
|
func (r *FeedRepo) FindByID(ctx context.Context, id int) (*domain.Feed, error) {
|
||||||
queryBuilder := r.db.squirrel.
|
queryBuilder := r.db.squirrel.
|
||||||
Select(
|
Select(
|
||||||
"id",
|
"f.id",
|
||||||
"indexer",
|
"i.identifier",
|
||||||
"name",
|
"f.name",
|
||||||
"type",
|
"f.type",
|
||||||
"enabled",
|
"f.enabled",
|
||||||
"url",
|
"f.url",
|
||||||
"interval",
|
"f.interval",
|
||||||
"timeout",
|
"f.timeout",
|
||||||
"max_age",
|
"f.max_age",
|
||||||
"api_key",
|
"f.api_key",
|
||||||
"cookie",
|
"f.cookie",
|
||||||
"created_at",
|
"f.created_at",
|
||||||
"updated_at",
|
"f.updated_at",
|
||||||
).
|
).
|
||||||
From("feed").
|
From("feed f").
|
||||||
Where("id = ?", id)
|
Join("indexer i ON f.indexer_id = i.id").
|
||||||
|
Where("f.id = ?", id)
|
||||||
|
|
||||||
query, args, err := queryBuilder.ToSql()
|
query, args, err := queryBuilder.ToSql()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -72,22 +73,23 @@ func (r *FeedRepo) FindByID(ctx context.Context, id int) (*domain.Feed, error) {
|
||||||
func (r *FeedRepo) FindByIndexerIdentifier(ctx context.Context, indexer string) (*domain.Feed, error) {
|
func (r *FeedRepo) FindByIndexerIdentifier(ctx context.Context, indexer string) (*domain.Feed, error) {
|
||||||
queryBuilder := r.db.squirrel.
|
queryBuilder := r.db.squirrel.
|
||||||
Select(
|
Select(
|
||||||
"id",
|
"f.id",
|
||||||
"indexer",
|
"i.identifier",
|
||||||
"name",
|
"f.name",
|
||||||
"type",
|
"f.type",
|
||||||
"enabled",
|
"f.enabled",
|
||||||
"url",
|
"f.url",
|
||||||
"interval",
|
"f.interval",
|
||||||
"timeout",
|
"f.timeout",
|
||||||
"max_age",
|
"f.max_age",
|
||||||
"api_key",
|
"f.api_key",
|
||||||
"cookie",
|
"f.cookie",
|
||||||
"created_at",
|
"f.created_at",
|
||||||
"updated_at",
|
"f.updated_at",
|
||||||
).
|
).
|
||||||
From("feed").
|
From("feed f").
|
||||||
Where("indexer = ?", indexer)
|
Join("indexer i ON f.indexer_id = i.id").
|
||||||
|
Where("i.name = ?", indexer)
|
||||||
|
|
||||||
query, args, err := queryBuilder.ToSql()
|
query, args, err := queryBuilder.ToSql()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -105,7 +107,6 @@ func (r *FeedRepo) FindByIndexerIdentifier(ctx context.Context, indexer string)
|
||||||
|
|
||||||
if err := row.Scan(&f.ID, &f.Indexer, &f.Name, &f.Type, &f.Enabled, &f.URL, &f.Interval, &f.Timeout, &f.MaxAge, &apiKey, &cookie, &f.CreatedAt, &f.UpdatedAt); err != nil {
|
if err := row.Scan(&f.ID, &f.Indexer, &f.Name, &f.Type, &f.Enabled, &f.URL, &f.Interval, &f.Timeout, &f.MaxAge, &apiKey, &cookie, &f.CreatedAt, &f.UpdatedAt); err != nil {
|
||||||
return nil, errors.Wrap(err, "error scanning row")
|
return nil, errors.Wrap(err, "error scanning row")
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
f.ApiKey = apiKey.String
|
f.ApiKey = apiKey.String
|
||||||
|
@ -117,24 +118,25 @@ func (r *FeedRepo) FindByIndexerIdentifier(ctx context.Context, indexer string)
|
||||||
func (r *FeedRepo) Find(ctx context.Context) ([]domain.Feed, error) {
|
func (r *FeedRepo) Find(ctx context.Context) ([]domain.Feed, error) {
|
||||||
queryBuilder := r.db.squirrel.
|
queryBuilder := r.db.squirrel.
|
||||||
Select(
|
Select(
|
||||||
"id",
|
"f.id",
|
||||||
"indexer",
|
"i.identifier",
|
||||||
"name",
|
"f.name",
|
||||||
"type",
|
"f.type",
|
||||||
"enabled",
|
"f.enabled",
|
||||||
"url",
|
"f.url",
|
||||||
"interval",
|
"f.interval",
|
||||||
"timeout",
|
"f.timeout",
|
||||||
"max_age",
|
"f.max_age",
|
||||||
"api_key",
|
"f.api_key",
|
||||||
"cookie",
|
"f.cookie",
|
||||||
"last_run",
|
"f.last_run",
|
||||||
"last_run_data",
|
"f.last_run_data",
|
||||||
"created_at",
|
"f.created_at",
|
||||||
"updated_at",
|
"f.updated_at",
|
||||||
).
|
).
|
||||||
From("feed").
|
From("feed f").
|
||||||
OrderBy("name ASC")
|
Join("indexer i ON f.indexer_id = i.id").
|
||||||
|
OrderBy("f.name ASC")
|
||||||
|
|
||||||
query, args, err := queryBuilder.ToSql()
|
query, args, err := queryBuilder.ToSql()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -175,7 +177,6 @@ func (r *FeedRepo) Store(ctx context.Context, feed *domain.Feed) error {
|
||||||
Insert("feed").
|
Insert("feed").
|
||||||
Columns(
|
Columns(
|
||||||
"name",
|
"name",
|
||||||
"indexer",
|
|
||||||
"type",
|
"type",
|
||||||
"enabled",
|
"enabled",
|
||||||
"url",
|
"url",
|
||||||
|
@ -186,7 +187,6 @@ func (r *FeedRepo) Store(ctx context.Context, feed *domain.Feed) error {
|
||||||
).
|
).
|
||||||
Values(
|
Values(
|
||||||
feed.Name,
|
feed.Name,
|
||||||
feed.Indexer,
|
|
||||||
feed.Type,
|
feed.Type,
|
||||||
feed.Enabled,
|
feed.Enabled,
|
||||||
feed.URL,
|
feed.URL,
|
||||||
|
@ -212,7 +212,6 @@ func (r *FeedRepo) Update(ctx context.Context, feed *domain.Feed) error {
|
||||||
queryBuilder := r.db.squirrel.
|
queryBuilder := r.db.squirrel.
|
||||||
Update("feed").
|
Update("feed").
|
||||||
Set("name", feed.Name).
|
Set("name", feed.Name).
|
||||||
Set("indexer", feed.Indexer).
|
|
||||||
Set("type", feed.Type).
|
Set("type", feed.Type).
|
||||||
Set("enabled", feed.Enabled).
|
Set("enabled", feed.Enabled).
|
||||||
Set("url", feed.URL).
|
Set("url", feed.URL).
|
||||||
|
|
|
@ -69,22 +69,17 @@ func NewService(log logger.Logger, config *domain.Config, repo domain.IndexerRep
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *service) Store(ctx context.Context, indexer domain.Indexer) (*domain.Indexer, error) {
|
func (s *service) Store(ctx context.Context, indexer domain.Indexer) (*domain.Indexer, error) {
|
||||||
identifier := indexer.Identifier
|
|
||||||
|
|
||||||
|
// if indexer is rss or torznab do additional cleanup for identifier
|
||||||
switch indexer.Implementation {
|
switch indexer.Implementation {
|
||||||
case "torznab":
|
case "torznab", "rss":
|
||||||
// if the name already contains torznab remove it
|
// make lowercase
|
||||||
cleanName := strings.ReplaceAll(strings.ToLower(indexer.Name), "torznab", "")
|
cleanName := strings.ToLower(indexer.Name)
|
||||||
identifier = slug.Make(fmt.Sprintf("%v-%v", indexer.Implementation, cleanName)) // torznab-name
|
|
||||||
|
|
||||||
case "rss":
|
// torznab-name OR rss-name
|
||||||
// if the name already contains rss remove it
|
indexer.Identifier = slug.Make(fmt.Sprintf("%v-%v", indexer.Implementation, cleanName))
|
||||||
cleanName := strings.ReplaceAll(strings.ToLower(indexer.Name), "rss", "")
|
|
||||||
identifier = slug.Make(fmt.Sprintf("%v-%v", indexer.Implementation, cleanName)) // rss-name
|
|
||||||
}
|
}
|
||||||
|
|
||||||
indexer.Identifier = identifier
|
|
||||||
|
|
||||||
i, err := s.repo.Store(ctx, indexer)
|
i, err := s.repo.Store(ctx, indexer)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
s.log.Error().Stack().Err(err).Msgf("failed to store indexer: %v", indexer.Name)
|
s.log.Error().Stack().Err(err).Msgf("failed to store indexer: %v", indexer.Name)
|
||||||
|
@ -92,8 +87,7 @@ func (s *service) Store(ctx context.Context, indexer domain.Indexer) (*domain.In
|
||||||
}
|
}
|
||||||
|
|
||||||
// add to indexerInstances
|
// add to indexerInstances
|
||||||
err = s.addIndexer(*i)
|
if err = s.addIndexer(*i); err != nil {
|
||||||
if err != nil {
|
|
||||||
s.log.Error().Stack().Err(err).Msgf("failed to add indexer: %v", indexer.Name)
|
s.log.Error().Stack().Err(err).Msgf("failed to add indexer: %v", indexer.Name)
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,13 +2,13 @@ import { Fragment, useState } from "react";
|
||||||
import { toast } from "react-hot-toast";
|
import { toast } from "react-hot-toast";
|
||||||
import { useMutation, useQuery } from "react-query";
|
import { useMutation, useQuery } from "react-query";
|
||||||
import Select, { components, ControlProps, InputProps, MenuProps, OptionProps } from "react-select";
|
import Select, { components, ControlProps, InputProps, MenuProps, OptionProps } from "react-select";
|
||||||
import type { FieldProps, FormikErrors } from "formik";
|
import type { FieldProps } from "formik";
|
||||||
import { Field, Form, Formik, FormikValues } from "formik";
|
import { Field, Form, Formik, FormikValues } from "formik";
|
||||||
|
|
||||||
import { XMarkIcon } from "@heroicons/react/24/solid";
|
import { XMarkIcon } from "@heroicons/react/24/solid";
|
||||||
import { Dialog, Transition } from "@headlessui/react";
|
import { Dialog, Transition } from "@headlessui/react";
|
||||||
|
|
||||||
import { sleep, slugify } from "../../utils";
|
import { sleep } from "../../utils";
|
||||||
import { queryClient } from "../../App";
|
import { queryClient } from "../../App";
|
||||||
import DEBUG from "../../components/debug";
|
import DEBUG from "../../components/debug";
|
||||||
import { APIClient } from "../../api/APIClient";
|
import { APIClient } from "../../api/APIClient";
|
||||||
|
@ -183,15 +183,6 @@ const SettingFields = (ind: IndexerDefinition, indexer: string) => {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
function slugIdentifier(name: string, prefix?: string) {
|
|
||||||
const l = name.toLowerCase();
|
|
||||||
if (prefix && prefix !== "") {
|
|
||||||
const r = l.replaceAll(prefix, "");
|
|
||||||
return slugify(`${prefix}-${r}`);
|
|
||||||
}
|
|
||||||
return slugify(l);
|
|
||||||
}
|
|
||||||
|
|
||||||
type SelectValue = {
|
type SelectValue = {
|
||||||
label: string;
|
label: string;
|
||||||
value: string;
|
value: string;
|
||||||
|
@ -236,15 +227,11 @@ export function IndexerAddForm({ isOpen, toggle }: AddProps) {
|
||||||
);
|
);
|
||||||
|
|
||||||
const onSubmit = (formData: FormikValues) => {
|
const onSubmit = (formData: FormikValues) => {
|
||||||
console.log("form: ", formData);
|
|
||||||
const ind = data && data.find(i => i.identifier === formData.identifier);
|
const ind = data && data.find(i => i.identifier === formData.identifier);
|
||||||
if (!ind)
|
if (!ind)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (formData.implementation === "torznab") {
|
if (formData.implementation === "torznab") {
|
||||||
// create slug for indexer identifier as "torznab-indexer_name"
|
|
||||||
const name = slugIdentifier(formData.name, "torznab");
|
|
||||||
|
|
||||||
const createFeed: FeedCreate = {
|
const createFeed: FeedCreate = {
|
||||||
name: formData.name,
|
name: formData.name,
|
||||||
enabled: false,
|
enabled: false,
|
||||||
|
@ -253,7 +240,6 @@ export function IndexerAddForm({ isOpen, toggle }: AddProps) {
|
||||||
api_key: formData.feed.api_key,
|
api_key: formData.feed.api_key,
|
||||||
interval: 30,
|
interval: 30,
|
||||||
timeout: 60,
|
timeout: 60,
|
||||||
indexer: name,
|
|
||||||
indexer_id: 0
|
indexer_id: 0
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -266,12 +252,8 @@ export function IndexerAddForm({ isOpen, toggle }: AddProps) {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
return;
|
return;
|
||||||
}
|
|
||||||
|
|
||||||
if (formData.implementation === "rss") {
|
|
||||||
// create slug for indexer identifier as "torznab-indexer_name"
|
|
||||||
const name = slugIdentifier(formData.name, "rss");
|
|
||||||
|
|
||||||
|
} else if (formData.implementation === "rss") {
|
||||||
const createFeed: FeedCreate = {
|
const createFeed: FeedCreate = {
|
||||||
name: formData.name,
|
name: formData.name,
|
||||||
enabled: false,
|
enabled: false,
|
||||||
|
@ -279,7 +261,6 @@ export function IndexerAddForm({ isOpen, toggle }: AddProps) {
|
||||||
url: formData.feed.url,
|
url: formData.feed.url,
|
||||||
interval: 30,
|
interval: 30,
|
||||||
timeout: 60,
|
timeout: 60,
|
||||||
indexer: name,
|
|
||||||
indexer_id: 0
|
indexer_id: 0
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -292,10 +273,8 @@ export function IndexerAddForm({ isOpen, toggle }: AddProps) {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
return;
|
return;
|
||||||
}
|
|
||||||
|
|
||||||
if (formData.implementation === "irc") {
|
|
||||||
|
|
||||||
|
} else if (formData.implementation === "irc") {
|
||||||
const channels: IrcChannel[] = [];
|
const channels: IrcChannel[] = [];
|
||||||
if (ind.irc?.channels.length) {
|
if (ind.irc?.channels.length) {
|
||||||
ind.irc.channels.forEach(element => {
|
ind.irc.channels.forEach(element => {
|
||||||
|
|
1
web/src/types/Feed.d.ts
vendored
1
web/src/types/Feed.d.ts
vendored
|
@ -19,7 +19,6 @@ interface Feed {
|
||||||
type FeedType = "TORZNAB" | "RSS";
|
type FeedType = "TORZNAB" | "RSS";
|
||||||
|
|
||||||
interface FeedCreate {
|
interface FeedCreate {
|
||||||
indexer: string;
|
|
||||||
name: string;
|
name: string;
|
||||||
type: FeedType;
|
type: FeedType;
|
||||||
enabled: boolean;
|
enabled: boolean;
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue