diff --git a/src/webui/api/appcontroller.cpp b/src/webui/api/appcontroller.cpp index dd91bced5..5b114c9ce 100644 --- a/src/webui/api/appcontroller.cpp +++ b/src/webui/api/appcontroller.cpp @@ -30,10 +30,14 @@ #include "appcontroller.h" +#include + #include #include +#include #include #include +#include #include #include #include @@ -250,6 +254,66 @@ void AppController::preferencesAction() data["rss_processing_enabled"] = RSS::Session::instance()->isProcessingEnabled(); data["rss_auto_downloading_enabled"] = RSS::AutoDownloader::instance()->isProcessingEnabled(); + // Advanced settings + // qBitorrent preferences + // Current network interface + data["current_network_interface"] = session->networkInterface(); + // Current network interface address + data["current_interface_address"] = BitTorrent::Session::instance()->networkInterfaceAddress(); + // Listen on IPv6 address + data["listen_on_ipv6_address"] = session->isIPv6Enabled(); + // Save resume data interval + data["save_resume_data_interval"] = session->saveResumeDataInterval(); + // Recheck completed torrents + data["recheck_completed_torrents"] = pref->recheckTorrentsOnCompletion(); + // Resolve peer countries + data["resolve_peer_countries"] = pref->resolvePeerCountries(); + + // libtorrent preferences + // Async IO threads + data["async_io_threads"] = session->asyncIOThreads(); + // File pool size + data["file_pool_size"] = session->filePoolSize(); + // Checking memory usage + data["checking_memory_use"] = session->checkingMemUsage(); + // Disk write cache + data["disk_cache"] = session->diskCacheSize(); + data["disk_cache_ttl"] = session->diskCacheTTL(); + // Enable OS cache + data["enable_os_cache"] = session->useOSCache(); + // Guided read cache + data["enable_guided_read_cache"] = session->isGuidedReadCacheEnabled(); + // Coalesce reads & writes + data["enable_coalesce_read_write"] = session->isCoalesceReadWriteEnabled(); + // Suggest mode + data["enable_upload_suggestions"] = session->isSuggestModeEnabled(); + // Send buffer watermark + data["send_buffer_watermark"] = session->sendBufferWatermark(); + data["send_buffer_low_watermark"] = session->sendBufferLowWatermark(); + data["send_buffer_watermark_factor"] = session->sendBufferWatermarkFactor(); + // Socket listen backlog size + data["socket_backlog_size"] = session->socketBacklogSize(); + // Outgoing ports + data["outgoing_ports_min"] = session->outgoingPortsMin(); + data["outgoing_ports_max"] = session->outgoingPortsMax(); + // uTP-TCP mixed mode + data["utp_tcp_mixed_mode"] = static_cast(session->utpMixedMode()); + // Multiple connections per IP + data["enable_multi_connections_from_same_ip"] = session->multiConnectionsPerIpEnabled(); + // Embedded tracker + data["enable_embedded_tracker"] = session->isTrackerEnabled(); + data["embedded_tracker_port"] = pref->getTrackerPort(); + // Choking algorithm + data["upload_slots_behavior"] = static_cast(session->chokingAlgorithm()); + // Seed choking algorithm + data["upload_choking_algorithm"] = static_cast(session->seedChokingAlgorithm()); + // Super seeding + data["enable_super_seeding"] = session->isSuperSeedingEnabled(); + // Announce + data["announce_to_all_trackers"] = session->announceToAllTrackers(); + data["announce_to_all_tiers"] = session->announceToAllTiers(); + data["announce_ip"] = session->announceIP(); + setResult(QJsonObject::fromVariantMap(data)); } @@ -576,9 +640,150 @@ void AppController::setPreferencesAction() RSS::Session::instance()->setProcessingEnabled(it.value().toBool()); if (hasKey("rss_auto_downloading_enabled")) RSS::AutoDownloader::instance()->setProcessingEnabled(it.value().toBool()); + + // Advanced settings + // qBittorrent preferences + // Current network interface + if (hasKey("current_network_interface")) { + const QString ifaceValue {it.value().toString()}; + + const QList ifaces = QNetworkInterface::allInterfaces(); + const auto ifacesIter = std::find_if(ifaces.cbegin(), ifaces.cend(), [&ifaceValue](const QNetworkInterface &iface) + { + return (!iface.addressEntries().isEmpty()) && (iface.name() == ifaceValue); + }); + const QString ifaceName = (ifacesIter != ifaces.cend()) ? ifacesIter->humanReadableName() : QString {}; + + session->setNetworkInterface(ifaceValue); + session->setNetworkInterfaceName(ifaceName); + } + // Current network interface address + if (hasKey("current_interface_address")) { + const QHostAddress ifaceAddress {it.value().toString().trimmed()}; + session->setNetworkInterfaceAddress(ifaceAddress.isNull() ? QString {} : ifaceAddress.toString()); + } + // Listen on IPv6 address + if (hasKey("listen_on_ipv6_address")) + session->setIPv6Enabled(it.value().toBool()); + // Save resume data interval + if (hasKey("save_resume_data_interval")) + session->setSaveResumeDataInterval(it.value().toInt()); + // Recheck completed torrents + if (hasKey("recheck_completed_torrents")) + pref->recheckTorrentsOnCompletion(it.value().toBool()); + // Resolve peer countries + if (hasKey("resolve_peer_countries")) + pref->resolvePeerCountries(it.value().toBool()); + + // libtorrent preferences + // Async IO threads + if (hasKey("async_io_threads")) + session->setAsyncIOThreads(it.value().toInt()); + // File pool size + if (hasKey("file_pool_size")) + session->setFilePoolSize(it.value().toInt()); + // Checking Memory Usage + if (hasKey("checking_memory_use")) + session->setCheckingMemUsage(it.value().toInt()); + // Disk write cache + if (hasKey("disk_cache")) + session->setDiskCacheSize(it.value().toInt()); + if (hasKey("disk_cache_ttl")) + session->setDiskCacheTTL(it.value().toInt()); + // Enable OS cache + if (hasKey("enable_os_cache")) + session->setUseOSCache(it.value().toBool()); + // Guided read cache + if (hasKey("enable_guided_read_cache")) + session->setGuidedReadCacheEnabled(it.value().toBool()); + // Coalesce reads & writes + if (hasKey("enable_coalesce_read_write")) + session->setCoalesceReadWriteEnabled(it.value().toBool()); + // Suggest mode + if (hasKey("enable_upload_suggestions")) + session->setSuggestMode(it.value().toBool()); + // Send buffer watermark + if (hasKey("send_buffer_watermark")) + session->setSendBufferWatermark(it.value().toInt()); + if (hasKey("send_buffer_low_watermark")) + session->setSendBufferLowWatermark(it.value().toInt()); + if (hasKey("send_buffer_watermark_factor")) + session->setSendBufferWatermarkFactor(it.value().toInt()); + // Socket listen backlog size + if (hasKey("socket_backlog_size")) + session->setSocketBacklogSize(it.value().toInt()); + // Outgoing ports + if (hasKey("outgoing_ports_min")) + session->setOutgoingPortsMin(it.value().toInt()); + if (hasKey("outgoing_ports_max")) + session->setOutgoingPortsMax(it.value().toInt()); + // uTP-TCP mixed mode + if (hasKey("utp_tcp_mixed_mode")) + session->setUtpMixedMode(static_cast(it.value().toInt())); + // Multiple connections per IP + if (hasKey("enable_multi_connections_from_same_ip")) + session->setMultiConnectionsPerIpEnabled(it.value().toBool()); + // Embedded tracker + if (hasKey("enable_embedded_tracker")) + session->setTrackerEnabled(it.value().toBool()); + if (hasKey("embedded_tracker_port")) + pref->setTrackerPort(it.value().toInt()); + // Choking algorithm + if (hasKey("upload_slots_behavior")) + session->setChokingAlgorithm(static_cast(it.value().toInt())); + // Seed choking algorithm + if (hasKey("upload_choking_algorithm")) + session->setSeedChokingAlgorithm(static_cast(it.value().toInt())); + // Super seeding + if (hasKey("enable_super_seeding")) + session->setSuperSeedingEnabled(it.value().toBool()); + // Announce + if (hasKey("announce_to_all_trackers")) + session->setAnnounceToAllTrackers(it.value().toBool()); + if (hasKey("announce_to_all_tiers")) + session->setAnnounceToAllTiers(it.value().toBool()); + if (hasKey("announce_ip")) { + const QHostAddress announceAddr {it.value().toString().trimmed()}; + session->setAnnounceIP(announceAddr.isNull() ? QString {} : announceAddr.toString()); + } } void AppController::defaultSavePathAction() { setResult(BitTorrent::Session::instance()->defaultSavePath()); } + +void AppController::networkInterfaceListAction() +{ + QVariantList ifaceList; + for (const QNetworkInterface &iface : asConst(QNetworkInterface::allInterfaces())) { + if (!iface.addressEntries().isEmpty()) { + ifaceList.append(QVariantMap { + {"name", iface.humanReadableName()}, + {"value", iface.name()} + }); + } + } + + setResult(QJsonArray::fromVariantList(ifaceList)); +} + +void AppController::networkInterfaceAddressListAction() +{ + checkParams({"iface"}); + + const QString ifaceName = params().value("iface"); + QVariantList addressList; + + if (ifaceName.isEmpty()) { + for (const QHostAddress &ip : asConst(QNetworkInterface::allAddresses())) + addressList.append(ip.toString()); + } + else { + const QNetworkInterface iface = QNetworkInterface::interfaceFromName(ifaceName); + for (const QNetworkAddressEntry &entry : asConst(iface.addressEntries())) + addressList.append(entry.ip().toString()); + } + + setResult(QJsonArray::fromVariantList(addressList)); +} diff --git a/src/webui/api/appcontroller.h b/src/webui/api/appcontroller.h index 63432bb6e..e0139613e 100644 --- a/src/webui/api/appcontroller.h +++ b/src/webui/api/appcontroller.h @@ -48,4 +48,7 @@ private slots: void preferencesAction(); void setPreferencesAction(); void defaultSavePathAction(); + + void networkInterfaceListAction(); + void networkInterfaceAddressListAction(); }; diff --git a/src/webui/www/private/preferences.html b/src/webui/www/private/preferences.html index 9f0a99dc6..e24a57162 100644 --- a/src/webui/www/private/preferences.html +++ b/src/webui/www/private/preferences.html @@ -20,6 +20,7 @@ +
@@ -50,6 +51,10 @@ $$('.PrefTab').addClass('invisible'); $('WebUITab').removeClass('invisible'); }); + $('PrefAdvancedLink').addEvent('click', function(e) { + $$('.PrefTab').addClass('invisible'); + $('AdvancedTab').removeClass('invisible'); + }); diff --git a/src/webui/www/private/preferences_content.html b/src/webui/www/private/preferences_content.html index a0ef0bc5b..6dc0ac9e0 100644 --- a/src/webui/www/private/preferences_content.html +++ b/src/webui/www/private/preferences_content.html @@ -817,6 +817,279 @@ + +