fix: correctly handle batch-adding trackers to multiple torrents (#5122)

This commit is contained in:
Charles Kerr 2023-03-02 00:33:49 -06:00 committed by GitHub
parent d3273504bd
commit 8fc904617b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 47 additions and 23 deletions

View File

@ -6,6 +6,8 @@
#include <algorithm>
#include <cassert>
#include <ctime>
#include <map>
#include <set>
#include <utility>
#include <QDateTime>
@ -28,6 +30,7 @@
#include <QTreeWidgetItem>
#include <libtransmission/transmission.h>
#include <libtransmission/announce-list.h>
#include <libtransmission/utils.h> // tr_getRatio()
#include "BaseDialog.h"
@ -1340,42 +1343,56 @@ void DetailsDialog::onTrackerSelectionChanged()
void DetailsDialog::onAddTrackerClicked()
{
bool ok = false;
QString const text = QInputDialog::getMultiLineText(
auto const text_qstr = QInputDialog::getMultiLineText(
this,
tr("Add URL(s)"),
tr("Add tracker announce URLs, one per line:"),
{},
&ok);
if (ok)
if (!ok)
{
QSet<QString> urls;
torrent_ids_t ids;
return;
}
for (auto const& line : text.split(QRegularExpression(QStringLiteral("[\r\n]+"))))
// for each URL entered by the user...
auto announce_list = tr_announce_list{};
announce_list.parse(text_qstr.toStdString());
auto url_to_ids = std::map<QString, std::set<tr_torrent_id_t>>{};
for (auto const& info : announce_list)
{
// for each selected torrent...
auto sv = info.announce.sv();
auto const announce_url = QString::fromUtf8(std::data(sv), std::size(sv));
for (auto const& id : ids_)
{
QString const url = line.trimmed();
if (!line.isEmpty() && QUrl(url).isValid())
// make a note if the torrent doesn't already have the URL
if (tracker_model_->find(id, announce_url) == -1)
{
for (auto const& id : ids_)
{
if (tracker_model_->find(id, url) == -1 && !urls.contains(url))
{
ids.insert(id);
urls.insert(url);
}
}
url_to_ids[announce_url].insert(id);
}
}
}
if (urls.isEmpty())
// now reverse the map so that if we're adding identical trackers
// to more than one torrent, that can be batched into a single call
auto ids_to_urls = std::map<std::set<tr_torrent_id_t>, std::set<QString>>{};
for (auto& [announce_url, ids] : url_to_ids)
{
ids_to_urls[ids].insert(announce_url);
}
if (std::empty(ids_to_urls))
{
QMessageBox::warning(this, tr("Error"), tr("No new URLs found."));
}
else
{
for (auto const& [ids, urls] : ids_to_urls)
{
QMessageBox::warning(this, tr("Error"), tr("No new URLs found."));
}
else
{
torrentSet(ids, TR_KEY_trackerAdd, urls.values());
torrentSet(
torrent_ids_t{ std::begin(ids), std::end(ids) },
TR_KEY_trackerAdd,
QList<QString>{ std::begin(urls), std::end(urls) });
}
}
}

View File

@ -5,6 +5,8 @@
#include <string_view>
#include <fmt/format.h>
#include "RpcClient.h"
#include <QApplication>
@ -160,6 +162,11 @@ void RpcClient::sendNetworkRequest(TrVariantPtr json, QFutureInterface<RpcRespon
void RpcClient::sendLocalRequest(TrVariantPtr json, QFutureInterface<RpcResponse> const& promise, int64_t tag)
{
if (verbose_)
{
fmt::print("{:s}:{:d} sending req:\n{:s}\n", __FILE__, __LINE__, tr_variantToStr(json.get(), TR_VARIANT_FMT_JSON));
}
local_requests_.insert(tag, promise);
tr_rpc_request_exec_json(session_, json.get(), localSessionCallback, this);
}