webui: manual add-from-feed/search endpoint; close RSS+Search (#6)

Add POST /api/rss/download so the UI can grab a torrent from a feed
article or a search result (magnet or .torrent URL) via the same tested
add path as the auto-downloader. Marks ISSUES #6 done.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
ookami125 2026-06-23 01:01:36 -04:00
parent d6e0e51175
commit 223354eff9
2 changed files with 24 additions and 1 deletions

View file

@ -3,7 +3,7 @@
- ✅ Adding a Category means I can't have none selected on adding a torrent. - ✅ Adding a Category means I can't have none selected on adding a torrent.
- ✅ Category default download location does nothing as changing it doesn't change the download location. Download location should be greyed out by default with the default location shown. Clicking should allow you to change the location. If the location is set it shouldn't change if the category is changed. - ✅ Category default download location does nothing as changing it doesn't change the download location. Download location should be greyed out by default with the default location shown. Clicking should allow you to change the location. If the location is set it shouldn't change if the category is changed.
- ✅ Automation variables at half window width makes the script unseeable. It should be displayed above the script if the window is to narrow. - ✅ Automation variables at half window width makes the script unseeable. It should be displayed above the script if the window is to narrow.
- We need to implement the RSS and Search Tabs. - We need to implement the RSS and Search Tabs.
- ✅ I need to be able to add Tags on adding a torrent. - ✅ I need to be able to add Tags on adding a torrent.
- ✅ Categories aren't saved across restart. - ✅ Categories aren't saved across restart.
- ✅ Pausing a torrent will go back into Downloading and Seeding. - ✅ Pausing a torrent will go back into Downloading and Seeding.

View file

@ -2263,6 +2263,27 @@ static void api_rss_rule(int fd, const char *body, size_t len, bool remove) {
api_rss_rules_list(fd); api_rss_rules_list(fd);
} }
/* POST /api/rss/download {magnet|torrentUrl, category, savePath, paused}
* Manually grab a torrent from a feed article or search result. Reuses the
* same add path as the auto-downloader (handles magnets and .torrent URLs). */
static void api_rss_download(int fd, const char *body, size_t len) {
json_t *req = read_body_json(body, len);
const char *magnet = json_string_or(req, "magnet", "");
const char *url = json_string_or(req, "torrentUrl", "");
const char *cat = json_string_or(req, "category", "");
const char *path = json_string_or(req, "savePath", "");
bool paused = json_boolean_value(json_object_get(req, "paused"));
bool ok = rss_download(magnet, url, cat, path, paused);
json_decref(req);
if (ok) {
json_t *reply = json_pack("{s:b}", "ok", 1);
http_json(fd, 200, reply);
json_decref(reply);
} else {
http_text(fd, 502, "Bad Gateway", "could not add torrent from this item");
}
}
/* POST /api/indexers upserts a Torznab indexer; .../delete removes one. */ /* POST /api/indexers upserts a Torznab indexer; .../delete removes one. */
static void api_indexer(int fd, const char *body, size_t len, bool remove) { static void api_indexer(int fd, const char *body, size_t len, bool remove) {
json_t *req = read_body_json(body, len); json_t *req = read_body_json(body, len);
@ -2629,6 +2650,8 @@ static void handle_api(int fd, const char *method, char *path,
api_rss_rule(fd, body, body_len, false); api_rss_rule(fd, body, body_len, false);
} else if (strcmp(path, "/api/rss/rules/delete") == 0 && strcmp(method, "POST") == 0) { } else if (strcmp(path, "/api/rss/rules/delete") == 0 && strcmp(method, "POST") == 0) {
api_rss_rule(fd, body, body_len, true); api_rss_rule(fd, body, body_len, true);
} else if (strcmp(path, "/api/rss/download") == 0 && strcmp(method, "POST") == 0) {
api_rss_download(fd, body, body_len);
} else if (strcmp(path, "/api/indexers") == 0 && strcmp(method, "POST") == 0) { } else if (strcmp(path, "/api/indexers") == 0 && strcmp(method, "POST") == 0) {
api_indexer(fd, body, body_len, false); api_indexer(fd, body, body_len, false);
} else if (strcmp(path, "/api/indexers/delete") == 0 && strcmp(method, "POST") == 0) { } else if (strcmp(path, "/api/indexers/delete") == 0 && strcmp(method, "POST") == 0) {