mirror of
https://github.com/transmission/transmission
synced 2025-02-20 13:16:53 +00:00
feat: default public trackers
This commit is contained in:
parent
f436d742a2
commit
7b377511a9
19 changed files with 265 additions and 3 deletions
|
@ -94,7 +94,7 @@ static struct event_base* ev_base = nullptr;
|
|||
**** Config File
|
||||
***/
|
||||
|
||||
static auto constexpr Options = std::array<tr_option, 43>{
|
||||
static auto constexpr Options = std::array<tr_option, 44>{
|
||||
{ { 'a', "allowed", "Allowed IP addresses. (Default: " TR_DEFAULT_RPC_WHITELIST ")", "a", true, "<list>" },
|
||||
{ 'b', "blocklist", "Enable peer blocklists", "b", false, nullptr },
|
||||
{ 'B', "no-blocklist", "Disable peer blocklists", "B", false, nullptr },
|
||||
|
@ -103,6 +103,7 @@ static auto constexpr Options = std::array<tr_option, 43>{
|
|||
{ 941, "incomplete-dir", "Where to store new torrents until they're complete", nullptr, true, "<directory>" },
|
||||
{ 942, "no-incomplete-dir", "Don't store incomplete torrents in a different location", nullptr, false, nullptr },
|
||||
{ 'd', "dump-settings", "Dump the settings and exit", "d", false, nullptr },
|
||||
{ 943, "default-trackers", "Trackers for public torrents to use automatically", nullptr, true, "<list>" },
|
||||
{ 'e', "logfile", "Dump the log messages to this filename", "e", true, "<filename>" },
|
||||
{ 'f', "foreground", "Run in the foreground instead of daemonizing", "f", false, nullptr },
|
||||
{ 'g', "config-dir", "Where to look for configuration files", "g", true, "<path>" },
|
||||
|
@ -416,6 +417,10 @@ static bool parse_args(
|
|||
tr_variantDictAddBool(settings, TR_KEY_incomplete_dir_enabled, false);
|
||||
break;
|
||||
|
||||
case 943:
|
||||
tr_variantDictAddStr(settings, TR_KEY_default_trackers, optstr);
|
||||
break;
|
||||
|
||||
case 'd':
|
||||
*dump_settings = true;
|
||||
break;
|
||||
|
|
|
@ -1022,6 +1022,10 @@ void Application::Impl::on_prefs_changed(tr_quark const key)
|
|||
tr_sessionSetEncryption(tr, static_cast<tr_encryption_mode>(gtr_pref_int_get(key)));
|
||||
break;
|
||||
|
||||
case TR_KEY_default_trackers:
|
||||
tr_sessionSetDefaultTrackers(tr, gtr_pref_string_get(key).c_str());
|
||||
break;
|
||||
|
||||
case TR_KEY_download_dir:
|
||||
tr_sessionSetDownloadDir(tr, gtr_pref_string_get(key).c_str());
|
||||
break;
|
||||
|
|
|
@ -176,6 +176,33 @@ Gtk::Entry* new_entry(tr_quark const key, Glib::RefPtr<Session> const& core)
|
|||
return w;
|
||||
}
|
||||
|
||||
void text_buffer_changed_cb(Glib::RefPtr<Gtk::TextBuffer> buffer, tr_quark const key, Glib::RefPtr<Session> const& core)
|
||||
{
|
||||
Gtk::TextBuffer::iterator start, end;
|
||||
buffer->get_bounds(start, end);
|
||||
core->set_pref(key, buffer->get_text(start, end, FALSE));
|
||||
}
|
||||
|
||||
Gtk::Widget* new_text_view(tr_quark const key, Glib::RefPtr<Session> const& core)
|
||||
{
|
||||
auto* w = Gtk::make_managed<Gtk::TextView>();
|
||||
auto buffer = w->get_buffer();
|
||||
|
||||
buffer->set_text(gtr_pref_string_get(key));
|
||||
|
||||
/* set up the scrolled window and put the text view in it */
|
||||
auto* scroll = Gtk::make_managed<Gtk::ScrolledWindow>();
|
||||
scroll->set_policy(Gtk::PolicyType::POLICY_AUTOMATIC, Gtk::PolicyType::POLICY_AUTOMATIC);
|
||||
scroll->set_shadow_type(Gtk::ShadowType::SHADOW_IN);
|
||||
scroll->add(*w);
|
||||
scroll->set_size_request(-1, 200);
|
||||
|
||||
/* signal */
|
||||
buffer->signal_changed().connect([buffer, key, core]() { text_buffer_changed_cb(buffer, key, core); });
|
||||
|
||||
return scroll;
|
||||
}
|
||||
|
||||
void chosen_cb(Gtk::FileChooser* w, tr_quark const key, Glib::RefPtr<Session> const& core)
|
||||
{
|
||||
core->set_pref(key, w->get_filename());
|
||||
|
@ -1051,6 +1078,11 @@ Gtk::Widget* PrefsDialog::Impl::networkPage()
|
|||
w->set_tooltip_text(_("LPD is a tool for finding peers on your local network."));
|
||||
t->add_wide_control(row, *w);
|
||||
|
||||
t->add_section_title(row, _("Default Trackers"));
|
||||
auto tv = new_text_view(TR_KEY_default_trackers, core_);
|
||||
tv->set_tooltip_text(_("Trackers for public torrents to use automatically"));
|
||||
t->add_wide_control(row, *tv);
|
||||
|
||||
return t;
|
||||
}
|
||||
|
||||
|
|
|
@ -18,7 +18,7 @@ using namespace std::literals;
|
|||
namespace
|
||||
{
|
||||
|
||||
auto constexpr my_static = std::array<std::string_view, 388>{ ""sv,
|
||||
auto constexpr my_static = std::array<std::string_view, 389>{ ""sv,
|
||||
"activeTorrentCount"sv,
|
||||
"activity-date"sv,
|
||||
"activityDate"sv,
|
||||
|
@ -74,6 +74,7 @@ auto constexpr my_static = std::array<std::string_view, 388>{ ""sv,
|
|||
"current-stats"sv,
|
||||
"date"sv,
|
||||
"dateCreated"sv,
|
||||
"default-trackers"sv,
|
||||
"delete-local-data"sv,
|
||||
"desiredAvailable"sv,
|
||||
"destination"sv,
|
||||
|
|
|
@ -77,6 +77,7 @@ enum
|
|||
TR_KEY_current_stats,
|
||||
TR_KEY_date,
|
||||
TR_KEY_dateCreated,
|
||||
TR_KEY_default_trackers,
|
||||
TR_KEY_delete_local_data,
|
||||
TR_KEY_desiredAvailable,
|
||||
TR_KEY_destination,
|
||||
|
|
|
@ -1789,6 +1789,11 @@ static char const* sessionSet(
|
|||
tr_sessionSetQueueStalledEnabled(session, boolVal);
|
||||
}
|
||||
|
||||
if (tr_variantDictFindStrView(args_in, TR_KEY_default_trackers, &sv))
|
||||
{
|
||||
session->setDefaultTrackers(sv);
|
||||
}
|
||||
|
||||
if (tr_variantDictFindInt(args_in, TR_KEY_download_queue_size, &i))
|
||||
{
|
||||
tr_sessionSetQueueSize(session, TR_DOWN, (int)i);
|
||||
|
@ -2071,6 +2076,10 @@ static void addSessionField(tr_session* s, tr_variant* d, tr_quark key)
|
|||
tr_variantDictAddStr(d, key, tr_sessionGetConfigDir(s));
|
||||
break;
|
||||
|
||||
case TR_KEY_default_trackers:
|
||||
tr_variantDictAddStr(d, key, s->defaultTrackers());
|
||||
break;
|
||||
|
||||
case TR_KEY_download_dir:
|
||||
tr_variantDictAddStr(d, key, s->downloadDir());
|
||||
break;
|
||||
|
|
|
@ -333,6 +333,7 @@ void tr_sessionGetDefaultSettings(tr_variant* d)
|
|||
tr_variantDictAddBool(d, TR_KEY_utp_enabled, true);
|
||||
tr_variantDictAddBool(d, TR_KEY_lpd_enabled, false);
|
||||
tr_variantDictAddStr(d, TR_KEY_download_dir, tr_getDefaultDownloadDir());
|
||||
tr_variantDictAddStr(d, TR_KEY_default_trackers, "");
|
||||
tr_variantDictAddInt(d, TR_KEY_speed_limit_down, 100);
|
||||
tr_variantDictAddBool(d, TR_KEY_speed_limit_down_enabled, false);
|
||||
tr_variantDictAddInt(d, TR_KEY_encryption, TR_DEFAULT_ENCRYPTION);
|
||||
|
@ -411,6 +412,7 @@ void tr_sessionGetSettings(tr_session const* s, tr_variant* d)
|
|||
tr_variantDictAddBool(d, TR_KEY_utp_enabled, s->isUTPEnabled);
|
||||
tr_variantDictAddBool(d, TR_KEY_lpd_enabled, s->isLPDEnabled);
|
||||
tr_variantDictAddStr(d, TR_KEY_download_dir, tr_sessionGetDownloadDir(s));
|
||||
tr_variantDictAddStr(d, TR_KEY_default_trackers, s->defaultTrackers());
|
||||
tr_variantDictAddInt(d, TR_KEY_download_queue_size, tr_sessionGetQueueSize(s, TR_DOWN));
|
||||
tr_variantDictAddBool(d, TR_KEY_download_queue_enabled, tr_sessionGetQueueEnabled(s, TR_DOWN));
|
||||
tr_variantDictAddInt(d, TR_KEY_speed_limit_down, tr_sessionGetSpeedLimit_KBps(s, TR_DOWN));
|
||||
|
@ -811,6 +813,11 @@ static void sessionSetImpl(void* vdata)
|
|||
tr_sessionSetCacheLimit_MB(session, i);
|
||||
}
|
||||
|
||||
if (tr_variantDictFindStrView(settings, TR_KEY_default_trackers, &sv))
|
||||
{
|
||||
session->setDefaultTrackers(sv);
|
||||
}
|
||||
|
||||
if (tr_variantDictFindInt(settings, TR_KEY_peer_limit_per_torrent, &i))
|
||||
{
|
||||
tr_sessionSetPeerLimitPerTorrent(session, i);
|
||||
|
@ -2244,6 +2251,53 @@ int tr_sessionGetCacheLimit_MB(tr_session const* session)
|
|||
****
|
||||
***/
|
||||
|
||||
void tr_session::setDefaultTrackers(std::string_view trackers)
|
||||
{
|
||||
/* keep the string */
|
||||
this->default_trackers_str_ = trackers;
|
||||
|
||||
/* clear out the old list entries */
|
||||
this->defaultTrackersList.clear();
|
||||
|
||||
/* build the new list entries */
|
||||
auto urlStart = std::string::npos;
|
||||
auto constexpr Delimiters = " ,;\r\n\t"sv;
|
||||
auto fragment = default_trackers_str_;
|
||||
while ((urlStart = fragment.find_first_not_of(Delimiters)) != std::string::npos)
|
||||
{
|
||||
auto urlEnd = fragment.find_first_of(Delimiters, urlStart);
|
||||
if (urlEnd == std::string::npos)
|
||||
{
|
||||
urlEnd = fragment.size() - 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
urlEnd -= 1;
|
||||
}
|
||||
this->defaultTrackersList.push_back(fragment.substr(urlStart, urlEnd));
|
||||
|
||||
if (fragment.size() > (urlEnd + 1))
|
||||
{
|
||||
fragment = fragment.substr(urlEnd + 1, fragment.size());
|
||||
}
|
||||
else
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void tr_sessionSetDefaultTrackers(tr_session* session, char const* trackers)
|
||||
{
|
||||
TR_ASSERT(tr_isSession(session));
|
||||
|
||||
session->setDefaultTrackers(trackers ? trackers : "");
|
||||
}
|
||||
|
||||
/***
|
||||
****
|
||||
***/
|
||||
|
||||
struct port_forwarding_data
|
||||
{
|
||||
bool enabled;
|
||||
|
|
|
@ -150,6 +150,15 @@ public:
|
|||
download_dir_ = dir;
|
||||
}
|
||||
|
||||
// default trackers
|
||||
|
||||
std::string const& defaultTrackers() const
|
||||
{
|
||||
return default_trackers_str_;
|
||||
}
|
||||
|
||||
void setDefaultTrackers(std::string_view trackers);
|
||||
|
||||
// incomplete dir
|
||||
|
||||
std::string const& incompleteDir() const
|
||||
|
@ -387,6 +396,8 @@ public:
|
|||
|
||||
std::unique_ptr<tr_rpc_server> rpc_server_;
|
||||
|
||||
std::list<std::string> defaultTrackersList;
|
||||
|
||||
// One of <netinet/ip.h>'s IPTOS_ values.
|
||||
// See tr_netTos*() in libtransmission/net.h for more info
|
||||
// Only session.cc should use this.
|
||||
|
@ -398,6 +409,7 @@ private:
|
|||
std::array<std::string, TR_SCRIPT_N_TYPES> scripts_;
|
||||
std::string blocklist_url_;
|
||||
std::string download_dir_;
|
||||
std::string default_trackers_str_;
|
||||
std::string incomplete_dir_;
|
||||
std::string peer_congestion_algorithm_;
|
||||
|
||||
|
|
|
@ -817,6 +817,52 @@ static void torrentInit(tr_torrent* tor, tr_ctor const* ctor)
|
|||
}
|
||||
}
|
||||
|
||||
static void tr_torrentAddDefaultTrackers(tr_torrent* tor)
|
||||
{
|
||||
std::list<std::string> trackerURLs = {};
|
||||
int numExistingTrackers = tr_torrentTrackerCount(tor);
|
||||
int numNewTrackers = tor->session->defaultTrackersList.size();
|
||||
|
||||
if (!numNewTrackers || tor->isPrivate())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// copy existing tracker URLs
|
||||
for (int i = 0; i < numExistingTrackers; ++i)
|
||||
{
|
||||
auto tracker = tr_torrentTracker(tor, i);
|
||||
trackerURLs.push_back(tracker.announce);
|
||||
}
|
||||
|
||||
// add the new ones
|
||||
for (std::string_view url : tor->session->defaultTrackersList)
|
||||
{
|
||||
if (tr_urlIsValidTracker(url))
|
||||
{
|
||||
// check for duplicates
|
||||
bool duplicate = false;
|
||||
for (auto trackerURL : trackerURLs)
|
||||
{
|
||||
if (trackerURL == url)
|
||||
{
|
||||
duplicate = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (duplicate)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
tor->announceList().add(url);
|
||||
}
|
||||
}
|
||||
/* tell the announcer to reload this torrent's tracker list */
|
||||
tr_announcerResetTorrent(tor->session->announcer, tor);
|
||||
}
|
||||
|
||||
tr_torrent* tr_torrentNew(tr_ctor* ctor, tr_torrent** setme_duplicate_of)
|
||||
{
|
||||
TR_ASSERT(ctor != nullptr);
|
||||
|
@ -843,6 +889,7 @@ tr_torrent* tr_torrentNew(tr_ctor* ctor, tr_torrent** setme_duplicate_of)
|
|||
|
||||
auto* const tor = new tr_torrent{ std::move(metainfo) };
|
||||
torrentInit(tor, ctor);
|
||||
tr_torrentAddDefaultTrackers(tor);
|
||||
return tor;
|
||||
}
|
||||
|
||||
|
|
|
@ -392,6 +392,8 @@ bool tr_sessionIsRPCPasswordEnabled(tr_session const* session);
|
|||
|
||||
char const* tr_sessionGetRPCBindAddress(tr_session const* session);
|
||||
|
||||
void tr_sessionSetDefaultTrackers(tr_session* session, char const* trackers);
|
||||
|
||||
enum tr_rpc_callback_type
|
||||
{
|
||||
TR_RPC_TORRENT_ADDED,
|
||||
|
|
|
@ -109,6 +109,7 @@ std::array<Prefs::PrefItem, Prefs::PREFS_COUNT> const Prefs::Items{
|
|||
{ ALT_SPEED_LIMIT_TIME_DAY, TR_KEY_alt_speed_time_day, QVariant::Int },
|
||||
{ BLOCKLIST_ENABLED, TR_KEY_blocklist_enabled, QVariant::Bool },
|
||||
{ BLOCKLIST_URL, TR_KEY_blocklist_url, QVariant::String },
|
||||
{ DEFAULT_TRACKERS, TR_KEY_default_trackers, QVariant::String },
|
||||
{ DSPEED, TR_KEY_speed_limit_down, QVariant::Int },
|
||||
{ DSPEED_ENABLED, TR_KEY_speed_limit_down_enabled, QVariant::Bool },
|
||||
{ DOWNLOAD_DIR, TR_KEY_download_dir, QVariant::String },
|
||||
|
|
|
@ -83,6 +83,7 @@ public:
|
|||
ALT_SPEED_LIMIT_TIME_DAY,
|
||||
BLOCKLIST_ENABLED,
|
||||
BLOCKLIST_URL,
|
||||
DEFAULT_TRACKERS,
|
||||
DSPEED,
|
||||
DSPEED_ENABLED,
|
||||
DOWNLOAD_DIR,
|
||||
|
|
|
@ -190,6 +190,10 @@ bool PrefsDialog::updateWidgetValue(QWidget* widget, int pref_key) const
|
|||
{
|
||||
pref_widget.as<FreeSpaceLabel>()->setPath(prefs_.getString(pref_key));
|
||||
}
|
||||
else if (pref_widget.is<QPlainTextEdit>())
|
||||
{
|
||||
pref_widget.as<QPlainTextEdit>()->setPlainText(prefs_.getString(pref_key));
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
|
@ -233,6 +237,14 @@ void PrefsDialog::linkWidgetToPref(QWidget* widget, int pref_key)
|
|||
if (auto const* spin_box = qobject_cast<QAbstractSpinBox*>(widget); spin_box != nullptr)
|
||||
{
|
||||
connect(spin_box, &QAbstractSpinBox::editingFinished, this, &PrefsDialog::spinBoxEditingFinished);
|
||||
return;
|
||||
}
|
||||
|
||||
auto const* plain_text_edit = qobject_cast<QPlainTextEdit*>(widget);
|
||||
if (plain_text_edit != nullptr)
|
||||
{
|
||||
connect(plain_text_edit, &QPlainTextEdit::textChanged, this, &PrefsDialog::plainTextChanged);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -295,6 +307,22 @@ void PrefsDialog::pathChanged(QString const& path)
|
|||
}
|
||||
}
|
||||
|
||||
void PrefsDialog::plainTextChanged()
|
||||
{
|
||||
PreferenceWidget const pref_widget(sender());
|
||||
|
||||
if (pref_widget.is<QPlainTextEdit>())
|
||||
{
|
||||
auto const* const plain_text_edit = pref_widget.as<QPlainTextEdit>();
|
||||
|
||||
if (plain_text_edit->document()->isModified())
|
||||
{
|
||||
prefs_.set(pref_widget.getPrefKey(), plain_text_edit->toPlainText());
|
||||
// we avoid using setPref() because the included refreshPref() call would reset the cursor while we're editing
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/***
|
||||
****
|
||||
***/
|
||||
|
@ -423,6 +451,7 @@ void PrefsDialog::initNetworkTab()
|
|||
linkWidgetToPref(ui_.enablePexCheck, Prefs::PEX_ENABLED);
|
||||
linkWidgetToPref(ui_.enableDhtCheck, Prefs::DHT_ENABLED);
|
||||
linkWidgetToPref(ui_.enableLpdCheck, Prefs::LPD_ENABLED);
|
||||
linkWidgetToPref(ui_.defaultTrackersPlainTextEdit, Prefs::DEFAULT_TRACKERS);
|
||||
|
||||
auto* cr = new ColumnResizer(this);
|
||||
cr->addLayout(ui_.incomingPeersSectionLayout);
|
||||
|
@ -775,11 +804,15 @@ void PrefsDialog::refreshPref(int key)
|
|||
{
|
||||
QWidget* w(it.value());
|
||||
|
||||
w->blockSignals(true);
|
||||
|
||||
if (!updateWidgetValue(w, key) && (key == Prefs::ENCRYPTION))
|
||||
{
|
||||
auto* combo_box = qobject_cast<QComboBox*>(w);
|
||||
int const index = combo_box->findData(prefs_.getInt(key));
|
||||
combo_box->setCurrentIndex(index);
|
||||
}
|
||||
|
||||
w->blockSignals(false);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -34,6 +34,7 @@ private slots:
|
|||
void timeEditingFinished();
|
||||
void lineEditingFinished();
|
||||
void pathChanged(QString const& path);
|
||||
void plainTextChanged();
|
||||
void refreshPref(int key);
|
||||
void encryptionEdited(int);
|
||||
void altSpeedDaysEdited(int);
|
||||
|
|
|
@ -983,6 +983,26 @@
|
|||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLabel" name="defaultTrackersLabel">
|
||||
<property name="toolTip">
|
||||
<string>a list of default trackers to be added to new public torrents (and existing ones, after a reload)</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Default Trackers:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPlainTextEdit" name="defaultTrackersPlainTextEdit">
|
||||
<property name="lineWrapMode">
|
||||
<enum>QPlainTextEdit::NoWrap</enum>
|
||||
</property>
|
||||
<property name="plainText">
|
||||
<string notr="true"/>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
|
|
|
@ -155,6 +155,7 @@ void Session::updatePref(int key)
|
|||
case Prefs::BLOCKLIST_DATE:
|
||||
case Prefs::BLOCKLIST_ENABLED:
|
||||
case Prefs::BLOCKLIST_URL:
|
||||
case Prefs::DEFAULT_TRACKERS:
|
||||
case Prefs::DHT_ENABLED:
|
||||
case Prefs::DOWNLOAD_QUEUE_ENABLED:
|
||||
case Prefs::DOWNLOAD_QUEUE_SIZE:
|
||||
|
|
|
@ -94,7 +94,7 @@ TEST_F(RpcTest, sessionGet)
|
|||
EXPECT_TRUE(tr_variantDictFindDict(&response, TR_KEY_arguments, &args));
|
||||
|
||||
// what we expected
|
||||
auto const expected_keys = std::array<tr_quark, 57>{
|
||||
auto const expected_keys = std::array<tr_quark, 58>{
|
||||
TR_KEY_alt_speed_down,
|
||||
TR_KEY_alt_speed_enabled,
|
||||
TR_KEY_alt_speed_time_begin,
|
||||
|
@ -109,6 +109,7 @@ TEST_F(RpcTest, sessionGet)
|
|||
TR_KEY_blocklist_url,
|
||||
TR_KEY_cache_size_mb,
|
||||
TR_KEY_config_dir,
|
||||
TR_KEY_default_trackers,
|
||||
TR_KEY_dht_enabled,
|
||||
TR_KEY_download_dir,
|
||||
TR_KEY_download_dir_free_space,
|
||||
|
|
|
@ -63,6 +63,10 @@ export class PrefsDialog extends EventTarget {
|
|||
}
|
||||
|
||||
static _getValue(e) {
|
||||
if (e.tagName === 'TEXTAREA') {
|
||||
return e.value;
|
||||
}
|
||||
|
||||
switch (e.type) {
|
||||
case 'checkbox':
|
||||
case 'radio':
|
||||
|
@ -118,6 +122,15 @@ export class PrefsDialog extends EventTarget {
|
|||
const n = Formatter.number(value);
|
||||
element.innerHTML = `Blocklist has <span class="blocklist-size-number">${n}</span> rules`;
|
||||
setTextContent(this.elements.peers.blocklist_update_button, 'Update');
|
||||
} else if (element.tagName === 'TEXTAREA') {
|
||||
if (
|
||||
// eslint-disable-next-line eqeqeq
|
||||
element.value != value &&
|
||||
element !== document.activeElement
|
||||
) {
|
||||
element.value = value;
|
||||
element.dispatchEvent(new Event('change'));
|
||||
}
|
||||
} else {
|
||||
switch (element.type) {
|
||||
case 'checkbox':
|
||||
|
@ -646,7 +659,25 @@ export class PrefsDialog extends EventTarget {
|
|||
root.append(cal.root);
|
||||
const utp_check = cal.check;
|
||||
|
||||
label = document.createElement('div');
|
||||
label.textContent = 'Default trackers';
|
||||
label.classList.add('section-label');
|
||||
root.append(label);
|
||||
|
||||
label = document.createElement('label');
|
||||
label.textContent =
|
||||
'(added to new public torrents and to existing ones on reload):';
|
||||
root.append(label);
|
||||
|
||||
const textarea = document.createElement('textarea');
|
||||
textarea.dataset.key = 'default-trackers';
|
||||
textarea.id = 'default-trackers';
|
||||
label.setAttribute('for', textarea.id);
|
||||
root.append(textarea);
|
||||
const default_trackers_textarea = textarea;
|
||||
|
||||
return {
|
||||
default_trackers_textarea,
|
||||
port_forwarding_check,
|
||||
port_input,
|
||||
port_status_label,
|
||||
|
@ -714,6 +745,8 @@ export class PrefsDialog extends EventTarget {
|
|||
console.trace(`unhandled input: ${element.type}`);
|
||||
break;
|
||||
}
|
||||
} else if (element.tagName === 'TEXTAREA') {
|
||||
element.addEventListener('change', on_change);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
|
|
@ -762,6 +762,10 @@ $popup-top: 61px; // TODO: ugly that this is hardcoded
|
|||
grid-column: span 2;
|
||||
}
|
||||
|
||||
#default-trackers {
|
||||
height: 300px;
|
||||
}
|
||||
|
||||
.blocklist-size-label,
|
||||
.blocklist-update-button,
|
||||
.port-status {
|
||||
|
|
Loading…
Reference in a new issue